summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Fernandez <marcelofg55@gmail.com>2018-07-14 09:11:28 -0300
committerMarcelo Fernandez <marcelofg55@gmail.com>2018-07-21 09:09:42 -0300
commit7a5f9fc08ea4f25cd20e743a9a1ef5566246cf2c (patch)
treee0a023fdaf6fe0219590e0370ffc3123f7def42a
parentcfcb6e11f25adb13177ba08777263288a5ec6f61 (diff)
Added a new MIDIDriver class
-rw-r--r--core/bind/core_bind.cpp5
-rw-r--r--core/bind/core_bind.h2
-rw-r--r--core/global_constants.cpp10
-rw-r--r--core/os/input_event.cpp119
-rw-r--r--core/os/input_event.h56
-rw-r--r--core/os/midi_driver.cpp107
-rw-r--r--core/os/midi_driver.h59
-rw-r--r--core/os/os.cpp10
-rw-r--r--core/os/os.h2
-rw-r--r--drivers/SCsub5
-rw-r--r--drivers/alsamidi/SCsub8
-rw-r--r--drivers/alsamidi/alsa_midi.cpp201
-rw-r--r--drivers/alsamidi/alsa_midi.h69
-rw-r--r--drivers/coremidi/SCsub8
-rw-r--r--drivers/coremidi/core_midi.cpp105
-rw-r--r--drivers/coremidi/core_midi.h61
-rw-r--r--drivers/winmidi/SCsub8
-rw-r--r--drivers/winmidi/win_midi.cpp100
-rw-r--r--drivers/winmidi/win_midi.h61
-rw-r--r--platform/osx/detect.py4
-rw-r--r--platform/osx/os_osx.h2
-rw-r--r--platform/osx/os_osx.mm2
-rw-r--r--platform/windows/detect.py3
-rw-r--r--platform/windows/os_windows.cpp8
-rw-r--r--platform/windows/os_windows.h4
-rw-r--r--platform/x11/detect.py2
-rw-r--r--platform/x11/os_x11.cpp7
-rw-r--r--platform/x11/os_x11.h5
28 files changed, 1029 insertions, 4 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 7a14e85f20..af1d49ae8c 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -221,6 +221,10 @@ String _OS::get_audio_driver_name(int p_driver) const {
return OS::get_singleton()->get_audio_driver_name(p_driver);
}
+PoolStringArray _OS::get_connected_midi_inputs() {
+ return OS::get_singleton()->get_connected_midi_inputs();
+}
+
void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) {
OS::VideoMode vm;
@@ -1058,6 +1062,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name);
ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count);
ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name);
+ ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &_OS::get_connected_midi_inputs);
ClassDB::bind_method(D_METHOD("get_screen_count"), &_OS::get_screen_count);
ClassDB::bind_method(D_METHOD("get_current_screen"), &_OS::get_current_screen);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 48b7b74005..1729c23779 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -152,6 +152,8 @@ public:
virtual int get_audio_driver_count() const;
virtual String get_audio_driver_name(int p_driver) const;
+ virtual PoolStringArray get_connected_midi_inputs();
+
virtual int get_screen_count() const;
virtual int get_current_screen() const;
virtual void set_current_screen(int p_screen);
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 5b4dd05dbf..187813f9d0 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -89,6 +89,7 @@ VARIANT_ENUM_CAST(KeyList);
VARIANT_ENUM_CAST(KeyModifierMask);
VARIANT_ENUM_CAST(ButtonList);
VARIANT_ENUM_CAST(JoystickList);
+VARIANT_ENUM_CAST(MidiMessageList);
void register_global_constants() {
@@ -458,6 +459,15 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_L2);
BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_R2);
+ // midi
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_AFTERTOUCH);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CONTROL_CHANGE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PROGRAM_CHANGE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CHANNEL_PRESSURE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PITCH_BEND);
+
// error list
BIND_GLOBAL_ENUM_CONSTANT(OK);
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index ca6446d015..e94ccb4f48 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -1080,3 +1080,122 @@ InputEventPanGesture::InputEventPanGesture() {
delta = Vector2(0, 0);
}
+/////////////////////////////
+
+void InputEventMIDI::set_channel(const int p_channel) {
+
+ channel = p_channel;
+}
+
+int InputEventMIDI::get_channel() const {
+ return channel;
+}
+
+void InputEventMIDI::set_message(const int p_message) {
+
+ message = p_message;
+}
+
+int InputEventMIDI::get_message() const {
+ return message;
+}
+
+void InputEventMIDI::set_pitch(const int p_pitch) {
+
+ pitch = p_pitch;
+}
+
+int InputEventMIDI::get_pitch() const {
+ return pitch;
+}
+
+void InputEventMIDI::set_velocity(const int p_velocity) {
+
+ velocity = p_velocity;
+}
+
+int InputEventMIDI::get_velocity() const {
+ return velocity;
+}
+
+void InputEventMIDI::set_instrument(const int p_instrument) {
+
+ instrument = p_instrument;
+}
+
+int InputEventMIDI::get_instrument() const {
+ return instrument;
+}
+
+void InputEventMIDI::set_pressure(const int p_pressure) {
+
+ pressure = p_pressure;
+}
+
+int InputEventMIDI::get_pressure() const {
+ return pressure;
+}
+
+void InputEventMIDI::set_controller_number(const int p_controller_number) {
+
+ controller_number = p_controller_number;
+}
+
+int InputEventMIDI::get_controller_number() const {
+ return controller_number;
+}
+
+void InputEventMIDI::set_controller_value(const int p_controller_value) {
+
+ controller_value = p_controller_value;
+}
+
+int InputEventMIDI::get_controller_value() const {
+ return controller_value;
+}
+
+String InputEventMIDI::as_text() const {
+
+ return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")";
+}
+
+void InputEventMIDI::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_channel", "channel"), &InputEventMIDI::set_channel);
+ ClassDB::bind_method(D_METHOD("get_channel"), &InputEventMIDI::get_channel);
+ ClassDB::bind_method(D_METHOD("set_message", "message"), &InputEventMIDI::set_message);
+ ClassDB::bind_method(D_METHOD("get_message"), &InputEventMIDI::get_message);
+ ClassDB::bind_method(D_METHOD("set_pitch", "pitch"), &InputEventMIDI::set_pitch);
+ ClassDB::bind_method(D_METHOD("get_pitch"), &InputEventMIDI::get_pitch);
+ ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &InputEventMIDI::set_velocity);
+ ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventMIDI::get_velocity);
+ ClassDB::bind_method(D_METHOD("set_instrument", "instrument"), &InputEventMIDI::set_instrument);
+ ClassDB::bind_method(D_METHOD("get_instrument"), &InputEventMIDI::get_instrument);
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMIDI::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMIDI::get_pressure);
+ ClassDB::bind_method(D_METHOD("set_controller_number", "controller_number"), &InputEventMIDI::set_controller_number);
+ ClassDB::bind_method(D_METHOD("get_controller_number"), &InputEventMIDI::get_controller_number);
+ ClassDB::bind_method(D_METHOD("set_controller_value", "controller_value"), &InputEventMIDI::set_controller_value);
+ ClassDB::bind_method(D_METHOD("get_controller_value"), &InputEventMIDI::get_controller_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "channel"), "set_channel", "get_channel");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "message"), "set_message", "get_message");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pitch"), "set_pitch", "get_pitch");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "velocity"), "set_velocity", "get_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "instrument"), "set_instrument", "get_instrument");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value");
+}
+
+InputEventMIDI::InputEventMIDI() {
+
+ channel = 0;
+ message = 0;
+ pitch = 0;
+ velocity = 0;
+ instrument = 0;
+ pressure = 0;
+ controller_number = 0;
+ controller_value = 0;
+}
diff --git a/core/os/input_event.h b/core/os/input_event.h
index bd1a85ce29..04126fee77 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -140,6 +140,16 @@ enum JoystickList {
JOY_ANALOG_R2 = JOY_AXIS_7,
};
+enum MidiMessageList {
+ MIDI_MESSAGE_NOTE_OFF = 0x8,
+ MIDI_MESSAGE_NOTE_ON = 0x9,
+ MIDI_MESSAGE_AFTERTOUCH = 0xA,
+ MIDI_MESSAGE_CONTROL_CHANGE = 0xB,
+ MIDI_MESSAGE_PROGRAM_CHANGE = 0xC,
+ MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD,
+ MIDI_MESSAGE_PITCH_BEND = 0xE,
+};
+
/**
* Input Modifier Status
* for keyboard/mouse events.
@@ -525,4 +535,50 @@ public:
InputEventPanGesture();
};
+
+class InputEventMIDI : public InputEvent {
+ GDCLASS(InputEventMIDI, InputEvent)
+
+ int channel;
+ int message;
+ int pitch;
+ int velocity;
+ int instrument;
+ int pressure;
+ int controller_number;
+ int controller_value;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_channel(const int p_channel);
+ int get_channel() const;
+
+ void set_message(const int p_message);
+ int get_message() const;
+
+ void set_pitch(const int p_pitch);
+ int get_pitch() const;
+
+ void set_velocity(const int p_velocity);
+ int get_velocity() const;
+
+ void set_instrument(const int p_instrument);
+ int get_instrument() const;
+
+ void set_pressure(const int p_pressure);
+ int get_pressure() const;
+
+ void set_controller_number(const int p_controller_number);
+ int get_controller_number() const;
+
+ void set_controller_value(const int p_controller_value);
+ int get_controller_value() const;
+
+ virtual String as_text() const;
+
+ InputEventMIDI();
+};
+
#endif
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
new file mode 100644
index 0000000000..7b4f84473c
--- /dev/null
+++ b/core/os/midi_driver.cpp
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* midi_driver.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "midi_driver.h"
+
+#include "main/input_default.h"
+#include "os/os.h"
+
+MIDIDriver *MIDIDriver::singleton = NULL;
+MIDIDriver *MIDIDriver::get_singleton() {
+
+ return singleton;
+}
+
+void MIDIDriver::set_singleton() {
+
+ singleton = this;
+}
+
+void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) {
+
+ Ref<InputEventMIDI> event;
+ event.instance();
+
+ if (length >= 1) {
+ event->set_channel(data[0] & 0xF);
+ event->set_message(data[0] >> 4);
+ }
+
+ switch (event->get_message()) {
+ case MIDI_MESSAGE_AFTERTOUCH:
+ if (length >= 3) {
+ event->set_pitch(data[1]);
+ event->set_pressure(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_CONTROL_CHANGE:
+ if (length >= 3) {
+ event->set_controller_number(data[1]);
+ event->set_controller_value(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_NOTE_ON:
+ case MIDI_MESSAGE_NOTE_OFF:
+ case MIDI_MESSAGE_PITCH_BEND:
+ if (length >= 3) {
+ event->set_pitch(data[1]);
+ event->set_velocity(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_PROGRAM_CHANGE:
+ if (length >= 2) {
+ event->set_instrument(data[1]);
+ }
+ break;
+
+ case MIDI_MESSAGE_CHANNEL_PRESSURE:
+ if (length >= 2) {
+ event->set_pressure(data[1]);
+ }
+ break;
+ }
+
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ id->parse_input_event(event);
+}
+
+PoolStringArray MIDIDriver::get_connected_inputs() {
+
+ PoolStringArray list;
+ return list;
+}
+
+MIDIDriver::MIDIDriver() {
+
+ set_singleton();
+}
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
new file mode 100644
index 0000000000..1a3a67a411
--- /dev/null
+++ b/core/os/midi_driver.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* midi_driver.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MIDI_DRIVER_H
+#define MIDI_DRIVER_H
+
+#include "core/variant.h"
+#include "typedefs.h"
+/**
+ * Multi-Platform abstraction for accessing to MIDI.
+ */
+
+class MIDIDriver {
+
+ static MIDIDriver *singleton;
+
+public:
+ static MIDIDriver *get_singleton();
+ void set_singleton();
+
+ virtual Error open() = 0;
+ virtual void close() = 0;
+
+ virtual PoolStringArray get_connected_inputs();
+
+ static void receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length);
+
+ MIDIDriver();
+ virtual ~MIDIDriver() {}
+};
+
+#endif
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 89866e4044..8dcf0990fc 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -33,6 +33,7 @@
#include "dir_access.h"
#include "input.h"
#include "os/file_access.h"
+#include "os/midi_driver.h"
#include "project_settings.h"
#include "servers/audio_server.h"
#include "version_generated.gen.h"
@@ -672,6 +673,15 @@ List<String> OS::get_restart_on_exit_arguments() const {
return restart_commandline;
}
+PoolStringArray OS::get_connected_midi_inputs() {
+
+ if (MIDIDriver::get_singleton())
+ return MIDIDriver::get_singleton()->get_connected_inputs();
+
+ PoolStringArray list;
+ return list;
+}
+
OS::OS() {
void *volatile stack_bottom;
diff --git a/core/os/os.h b/core/os/os.h
index 4e0cb003fb..dd783408e8 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -189,6 +189,8 @@ public:
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
+ virtual PoolStringArray get_connected_midi_inputs();
+
virtual int get_screen_count() const { return 1; }
virtual int get_current_screen() const { return 0; }
virtual void set_current_screen(int p_screen) {}
diff --git a/drivers/SCsub b/drivers/SCsub
index 2c5e9434e8..f9cfa3fb05 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -21,6 +21,11 @@ if (env["platform"] == "windows"):
if env['xaudio2']:
SConscript("xaudio2/SCsub")
+# Midi drivers
+SConscript('alsamidi/SCsub')
+SConscript('coremidi/SCsub')
+SConscript('winmidi/SCsub')
+
# Graphics drivers
if (env["platform"] != "server"):
SConscript('gles3/SCsub')
diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/alsamidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp
new file mode 100644
index 0000000000..599470d7e0
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* alsa_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#include <errno.h>
+
+#include "alsa_midi.h"
+#include "os/os.h"
+#include "print_string.h"
+
+static int get_message_size(uint8_t message) {
+ switch (message & 0xF0) {
+ case 0x80: // note off
+ case 0x90: // note on
+ case 0xA0: // aftertouch
+ case 0xB0: // continuous controller
+ return 3;
+
+ case 0xC0: // patch change
+ case 0xD0: // channel pressure
+ case 0xE0: // pitch bend
+ return 2;
+ }
+
+ return 256;
+}
+
+void MIDIDriverALSAMidi::thread_func(void *p_udata) {
+ MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata;
+ uint64_t timestamp = 0;
+ uint8_t buffer[256];
+ int expected_size = 255;
+ int bytes = 0;
+
+ while (!md->exit_thread) {
+ int ret;
+
+ md->lock();
+
+ for (int i = 0; i < md->connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = md->connected_inputs[i];
+ do {
+ uint8_t byte = 0;
+ ret = snd_rawmidi_read(midi_in, &byte, 1);
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret)));
+ }
+ } else {
+ if (byte & 0x80) {
+ // Flush previous packet if there is any
+ if (bytes) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ expected_size = get_message_size(byte);
+ }
+
+ if (bytes < 256) {
+ buffer[bytes++] = byte;
+ // If we know the size of the current packet receive it if it reached the expected size
+ if (bytes >= expected_size) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ }
+ }
+ } while (ret > 0);
+ }
+
+ md->unlock();
+
+ OS::get_singleton()->delay_usec(1000);
+ }
+}
+
+Error MIDIDriverALSAMidi::open() {
+
+ void **hints;
+
+ if (snd_device_name_hint(-1, "rawmidi", &hints) < 0)
+ return ERR_CANT_OPEN;
+
+ int i = 0;
+ for (void **n = hints; *n != NULL; n++) {
+ char *name = snd_device_name_get_hint(*n, "NAME");
+
+ if (name != NULL) {
+ snd_rawmidi_t *midi_in;
+ int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK);
+ if (ret >= 0) {
+ connected_inputs.insert(i++, midi_in);
+ }
+ }
+
+ if (name != NULL)
+ free(name);
+ }
+ snd_device_name_free_hint(hints);
+
+ mutex = Mutex::create();
+ thread = Thread::create(MIDIDriverALSAMidi::thread_func, this);
+
+ return OK;
+}
+
+void MIDIDriverALSAMidi::close() {
+
+ if (thread) {
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
+
+ memdelete(thread);
+ thread = NULL;
+ }
+
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_close(midi_in);
+ }
+ connected_inputs.clear();
+}
+
+void MIDIDriverALSAMidi::lock() const {
+
+ if (mutex)
+ mutex->lock();
+}
+
+void MIDIDriverALSAMidi::unlock() const {
+
+ if (mutex)
+ mutex->unlock();
+}
+
+PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ lock();
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_info_t *info;
+
+ snd_rawmidi_info_malloc(&info);
+ snd_rawmidi_info(midi_in, info);
+ list.push_back(snd_rawmidi_info_get_name(info));
+ snd_rawmidi_info_free(info);
+ }
+ unlock();
+
+ return list;
+}
+
+MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
+
+ mutex = NULL;
+ thread = NULL;
+
+ exit_thread = false;
+}
+
+MIDIDriverALSAMidi::~MIDIDriverALSAMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h
new file mode 100644
index 0000000000..90e458a365
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* alsa_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#ifndef ALSA_MIDI_H
+#define ALSA_MIDI_H
+
+#include <alsa/asoundlib.h>
+#include <stdio.h>
+
+#include "core/os/mutex.h"
+#include "core/os/thread.h"
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverALSAMidi : public MIDIDriver {
+
+ Thread *thread;
+ Mutex *mutex;
+
+ Vector<snd_rawmidi_t *> connected_inputs;
+
+ bool exit_thread;
+
+ static void thread_func(void *p_udata);
+
+ void lock() const;
+ void unlock() const;
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverALSAMidi();
+ virtual ~MIDIDriverALSAMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/coremidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp
new file mode 100644
index 0000000000..3619be4a8e
--- /dev/null
+++ b/drivers/coremidi/core_midi.cpp
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* core_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#include "core_midi.h"
+#include "print_string.h"
+
+#include <CoreAudio/HostTime.h>
+#include <CoreServices/CoreServices.h>
+
+void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) {
+ MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet);
+ for (int i = 0; i < packet_list->numPackets; i++) {
+ receive_input_packet(packet->timeStamp, packet->data, packet->length);
+ packet = MIDIPacketNext(packet);
+ }
+}
+
+Error MIDIDriverCoreMidi::open() {
+
+ CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII);
+ OSStatus result = MIDIClientCreate(name, NULL, NULL, &client);
+ CFRelease(name);
+ if (result != noErr) {
+ ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result)));
+ return ERR_CANT_OPEN;
+ }
+
+ result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in);
+ if (result != noErr) {
+ ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result)));
+ return ERR_CANT_OPEN;
+ }
+
+ int sources = MIDIGetNumberOfSources();
+ for (int i = 0; i < sources; i++) {
+
+ MIDIEndpointRef source = MIDIGetSource(i);
+ if (source != NULL) {
+ MIDIPortConnectSource(port_in, source, (void *)this);
+ connected_sources.insert(i, source);
+ }
+ }
+
+ return OK;
+}
+
+void MIDIDriverCoreMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ MIDIEndpointRef source = connected_sources[i];
+ MIDIPortDisconnectSource(port_in, source);
+ }
+ connected_sources.clear();
+
+ if (port_in != 0) {
+ MIDIPortDispose(port_in);
+ port_in = 0;
+ }
+
+ if (client != 0) {
+ MIDIClientDispose(client);
+ client = 0;
+ }
+}
+
+MIDIDriverCoreMidi::MIDIDriverCoreMidi() {
+
+ client = 0;
+}
+
+MIDIDriverCoreMidi::~MIDIDriverCoreMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h
new file mode 100644
index 0000000000..fd35e12f4b
--- /dev/null
+++ b/drivers/coremidi/core_midi.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* core_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#ifndef CORE_MIDI_H
+#define CORE_MIDI_H
+
+#include <stdio.h>
+
+#include <CoreMIDI/CoreMIDI.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverCoreMidi : public MIDIDriver {
+
+ MIDIClientRef client;
+ MIDIPortRef port_in;
+
+ Vector<MIDIEndpointRef> connected_sources;
+
+ static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ MIDIDriverCoreMidi();
+ virtual ~MIDIDriverCoreMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/winmidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp
new file mode 100644
index 0000000000..6da6e31b2b
--- /dev/null
+++ b/drivers/winmidi/win_midi.cpp
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* win_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#include "win_midi.h"
+#include "print_string.h"
+
+void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
+
+ if (wMsg == MIM_DATA) {
+ receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3);
+ }
+}
+
+Error MIDIDriverWinMidi::open() {
+
+ for (UINT i = 0; i < midiInGetNumDevs(); i++) {
+ HMIDIIN midi_in;
+
+ MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION);
+ if (res == MMSYSERR_NOERROR) {
+ midiInStart(midi_in);
+ connected_sources.insert(i, midi_in);
+ } else {
+ char err[256];
+ midiInGetErrorText(res, err, 256);
+ ERR_PRINTS("midiInOpen error: " + String(err));
+ }
+ }
+
+ return OK;
+}
+
+PoolStringArray MIDIDriverWinMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ UINT id = 0;
+ MMRESULT res = midiInGetID(midi_in, &id);
+ if (res == MMSYSERR_NOERROR) {
+ MIDIINCAPS caps;
+ res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
+ if (res == MMSYSERR_NOERROR) {
+ list.push_back(caps.szPname);
+ }
+ }
+ }
+
+ return list;
+}
+
+void MIDIDriverWinMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ midiInStop(midi_in);
+ midiInClose(midi_in);
+ }
+ connected_sources.clear();
+}
+
+MIDIDriverWinMidi::MIDIDriverWinMidi() {
+}
+
+MIDIDriverWinMidi::~MIDIDriverWinMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h
new file mode 100644
index 0000000000..1cf9b19b5d
--- /dev/null
+++ b/drivers/winmidi/win_midi.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* win_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#ifndef WIN_MIDI_H
+#define WIN_MIDI_H
+
+#include <stdio.h>
+#include <windows.h>
+
+#include <mmsystem.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverWinMidi : public MIDIDriver {
+
+ Vector<HMIDIIN> connected_sources;
+
+ static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverWinMidi();
+ virtual ~MIDIDriverWinMidi();
+};
+
+#endif
+#endif
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 72b8aa99f8..8d372c210d 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -108,8 +108,8 @@ def configure(env):
## Flags
env.Append(CPPPATH=['#platform/osx'])
- env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
+ env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED'])
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMidi', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
env.Append(LIBS=['pthread'])
env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 3d14a6d4fb..686e3f8c90 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -33,6 +33,7 @@
#include "crash_handler_osx.h"
#include "drivers/coreaudio/audio_driver_coreaudio.h"
+#include "drivers/coremidi/core_midi.h"
#include "drivers/unix/os_unix.h"
#include "joypad_osx.h"
#include "main/input_default.h"
@@ -74,6 +75,7 @@ public:
IP_Unix *ip_unix;
AudioDriverCoreAudio audio_driver;
+ MIDIDriverCoreMidi midi_driver;
InputDefault *input;
JoypadOSX *joypad_osx;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 282f5e2d1b..e77f8b3173 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -1351,6 +1351,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
AudioDriverManager::initialize(p_audio_driver);
+ midi_driver.open();
+
input = memnew(InputDefault);
joypad_osx = memnew(JoypadOSX);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 05806d2fe8..617cc11991 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -200,7 +200,8 @@ def configure_msvc(env, manual_msvc_config):
env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED', 'OPENGL_ENABLED',
'RTAUDIO_ENABLED', 'WASAPI_ENABLED',
- 'TYPED_METHOD_BIND', 'WIN32', 'MSVC',
+ 'WINMIDI_ENABLED', 'TYPED_METHOD_BIND',
+ 'WIN32', 'MSVC',
{'WINVER' : '$target_win_version',
'_WIN32_WINNT': '$target_win_version'}])
if env["bits"] == "64":
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ac37e1246d..e083fd7323 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1219,6 +1219,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
AudioDriverManager::initialize(p_audio_driver);
+#ifdef WINMIDI_ENABLED
+ driver_midi.open();
+#endif
+
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -1347,6 +1351,10 @@ void OS_Windows::set_main_loop(MainLoop *p_main_loop) {
void OS_Windows::finalize() {
+#ifdef WINMIDI_ENABLED
+ driver_midi.close();
+#endif
+
if (main_loop)
memdelete(main_loop);
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index b99d3e3422..69c7d851b8 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -35,6 +35,7 @@
#include "crash_handler_win.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
+#include "drivers/winmidi/win_midi.h"
#include "os/input.h"
#include "os/os.h"
#include "power_windows.h"
@@ -144,6 +145,9 @@ class OS_Windows : public OS {
#ifdef XAUDIO2_ENABLED
AudioDriverXAudio2 driver_xaudio2;
#endif
+#ifdef WINMIDI_ENABLED
+ MIDIDriverWinMidi driver_midi;
+#endif
CrashHandler crash_handler;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 09e16ad078..89fba02698 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -240,7 +240,7 @@ def configure(env):
if (os.system("pkg-config --exists alsa") == 0): # 0 means found
print("Enabling ALSA")
- env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+ env.Append(CPPFLAGS=["-DALSA_ENABLED", "-DALSAMIDI_ENABLED"])
env.ParseConfig('pkg-config alsa --cflags --libs')
else:
print("ALSA libraries not found, disabling driver")
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index af0e02173f..260ce57732 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -342,6 +342,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
AudioDriverManager::initialize(p_audio_driver);
+#ifdef ALSAMIDI_ENABLED
+ driver_alsamidi.open();
+#endif
+
ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE);
@@ -606,6 +610,9 @@ void OS_X11::finalize() {
memdelete(debugger_connection_console);
}
*/
+#ifdef ALSAMIDI_ENABLED
+ driver_alsamidi.close();
+#endif
#ifdef JOYDEV_ENABLED
memdelete(joypad);
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index b67bc824be..44455a2d8d 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -38,6 +38,7 @@
#include "servers/visual_server.h"
//#include "servers/visual/visual_server_wrap_mt.h"
#include "drivers/alsa/audio_driver_alsa.h"
+#include "drivers/alsamidi/alsa_midi.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "joypad_linux.h"
#include "main/input_default.h"
@@ -168,6 +169,10 @@ class OS_X11 : public OS_Unix {
AudioDriverALSA driver_alsa;
#endif
+#ifdef ALSAMIDI_ENABLED
+ MIDIDriverALSAMidi driver_alsamidi;
+#endif
+
#ifdef PULSEAUDIO_ENABLED
AudioDriverPulseAudio driver_pulseaudio;
#endif