diff --git a/.gitignore b/.gitignore
index 8d537b993f..4176dcc652 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,5 +50,9 @@ interface/external/faceplus/*
interface/external/priovr/*
!interface/external/priovr/readme.txt
+# Ignore RtMidi
+interface/external/rtmidi/*
+!interface/external/rtmidi/readme.txt
+
# Ignore interfaceCache for Linux users
interface/interfaceCache/
diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake
new file mode 100644
index 0000000000..a54cc483e1
--- /dev/null
+++ b/cmake/modules/FindRtMidi.cmake
@@ -0,0 +1,33 @@
+#
+# FindRtMidd.cmake
+#
+# Try to find the RtMidi library
+#
+# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories
+#
+# Once done this will define
+#
+# RTMIDI_FOUND - system found RtMidi
+# RTMIDI_INCLUDE_DIRS - the RtMidi include directory
+# RTMIDI_CPP - Include this with src to use RtMidi
+#
+# Created on 6/30/2014 by Stephen Birarda
+# Copyright 2014 High Fidelity, Inc.
+#
+# Distributed under the Apache License, Version 2.0.
+# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+#
+
+if (RTMIDI_LIBRARIES AND RTMIDI_INCLUDE_DIRS)
+ # in cache already
+ set(RTMIDI_FOUND TRUE)
+else ()
+
+ set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi")
+
+ find_path(RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS})
+ find_file(RTMIDI_CPP NAMES RtMidi.cpp PATH_SUFFIXES src HINTS ${RTMIDI_SEARCH_DIRS})
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP)
+endif ()
\ No newline at end of file
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index cf203c41d9..35272ad22d 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -18,6 +18,7 @@ set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus")
set(PRIOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/priovr")
set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense")
set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage")
+set(RTMIDI_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/rtmidi")
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5LinguistToolsMacros)
@@ -110,6 +111,16 @@ if (APPLE)
SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns")
endif()
+# RtMidi for scripted MIDI control
+find_package(RtMidi)
+
+if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI)
+ add_definitions(-DHAVE_RTMIDI)
+ include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR})
+
+ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${RTMIDI_CPP}")
+endif ()
+
# create the executable, make it a bundle on OS X
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM})
@@ -143,71 +154,78 @@ find_package(Qxmpp)
# include the Sixense library for Razer Hydra if available
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
- add_definitions(-DHAVE_SIXENSE)
- include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}")
- if (APPLE OR UNIX)
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
- endif (APPLE OR UNIX)
- target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}")
+ add_definitions(-DHAVE_SIXENSE)
+ include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}")
+ if (APPLE OR UNIX)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
+ endif (APPLE OR UNIX)
+ target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}")
endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
# likewise with Visage library for webcam feature tracking
if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
- add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
- include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
- if (APPLE)
- add_definitions(-DMAC_OS_X)
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
- include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
- find_library(AVFoundation AVFoundation)
- find_library(CoreMedia CoreMedia)
- find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
- target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
- endif (APPLE)
- target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}")
+ add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
+ include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
+ if (APPLE)
+ add_definitions(-DMAC_OS_X)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
+ include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
+ find_library(AVFoundation AVFoundation)
+ find_library(CoreMedia CoreMedia)
+ find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
+ target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
+ endif (APPLE)
+ target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}")
endif (VISAGE_FOUND AND NOT DISABLE_VISAGE)
# and with Faceplus library, also for webcam feature tracking
if (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
- add_definitions(-DHAVE_FACEPLUS)
- include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}")
- target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}")
+ add_definitions(-DHAVE_FACEPLUS)
+ include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}")
+ target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}")
endif (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
# and with LibOVR for Oculus Rift
if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
- add_definitions(-DHAVE_LIBOVR)
- include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}")
-
- if (APPLE OR UNIX)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}")
- endif ()
-
- target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
+ add_definitions(-DHAVE_LIBOVR)
+ include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}")
+
+ if (APPLE OR UNIX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}")
+ endif ()
+
+ target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}")
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
# and with PrioVR library
if (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
- add_definitions(-DHAVE_PRIOVR)
- include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
- target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
+ add_definitions(-DHAVE_PRIOVR)
+ include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
+ target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
endif (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
# and with SDL for joysticks
if (SDL_FOUND AND NOT DISABLE_SDL)
- add_definitions(-DHAVE_SDL)
- include_directories(SYSTEM "${SDL_INCLUDE_DIR}")
- target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}")
+ add_definitions(-DHAVE_SDL)
+ include_directories(SYSTEM "${SDL_INCLUDE_DIR}")
+ target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}")
endif (SDL_FOUND AND NOT DISABLE_SDL)
# and with qxmpp for chat
if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
- add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
- include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
+ add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
+ include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
- target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
+ target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}")
endif (QXMPP_FOUND AND NOT DISABLE_QXMPP)
+# link CoreMIDI if we're using RtMidi
+if (RTMIDI_FOUND AND APPLE)
+ find_library(CoreMIDI CoreMIDI)
+ add_definitions(-D__MACOSX_CORE__)
+ target_link_libraries(${TARGET_NAME} ${CoreMIDI})
+endif()
+
# include headers for interface and InterfaceConfig.
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt
new file mode 100644
index 0000000000..d83d0c293e
--- /dev/null
+++ b/interface/external/rtmidi/readme.txt
@@ -0,0 +1,41 @@
+
+Instructions for adding the RtMidi library to Interface
+Stephen Birarda, June 30, 2014
+
+1. Download the RtMidi tarball from High Fidelity S3.
+ http://highfidelity-public.s3.amazonaws.com/dependencies/rtmidi-2.1.0.tar.gz
+
+2. Copy RtMidi.h to externals/rtmidi/include.
+
+3. Copy RtMidi.cpp to externals/rtmidi/src
+
+4. Delete your build directory, run cmake and build, and you should be all set.
+
+=========================
+
+RtMidi: realtime MIDI i/o C++ classes
+Copyright (c) 2003-2014 Gary P. Scavone
+
+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.
+
+Any person wishing to distribute modifications to the Software is
+asked to send the modifications to the original developer so that
+they can be incorporated into the canonical version. This is,
+however, not a binding provision of this license.
+
+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.
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 9bc08aa188..d0a8bb15dd 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -69,6 +69,7 @@
#include "Menu.h"
#include "ModelUploader.h"
#include "Util.h"
+#include "devices/MIDIManager.h"
#include "devices/OculusManager.h"
#include "devices/TV3DManager.h"
#include "renderer/ProgramObject.h"
@@ -393,6 +394,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig();
_trayIcon->show();
+
+ // setup the MIDIManager
+ MIDIManager& midiManagerInstance = MIDIManager::getInstance();
+ midiManagerInstance.openDefaultPort();
}
Application::~Application() {
@@ -3600,6 +3605,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript
scriptEngine->registerGlobalObject("AnimationCache", &_animationCache);
scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector);
scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance());
+ scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance());
QThread* workerThread = new QThread(this);
diff --git a/interface/src/devices/MIDIManager.cpp b/interface/src/devices/MIDIManager.cpp
new file mode 100644
index 0000000000..f88bcd1d3d
--- /dev/null
+++ b/interface/src/devices/MIDIManager.cpp
@@ -0,0 +1,64 @@
+//
+// MIDIManager.cpp
+//
+//
+// Created by Stephen Birarda on 2014-06-30.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include
+
+#include "MIDIManager.h"
+
+MIDIManager& MIDIManager::getInstance() {
+ static MIDIManager sharedInstance;
+ return sharedInstance;
+}
+
+void MIDIManager::midiCallback(double deltaTime, std::vector* message, void* userData) {
+
+ MIDIEvent callbackEvent;
+ callbackEvent.deltaTime = deltaTime;
+
+ callbackEvent.type = message->at(0);
+
+ if (message->size() > 1) {
+ callbackEvent.data1 = message->at(1);
+ }
+
+ if (message->size() > 2) {
+ callbackEvent.data2 = message->at(2);
+ }
+
+ emit getInstance().midiEvent(callbackEvent);
+}
+
+MIDIManager::~MIDIManager() {
+ delete _midiInput;
+}
+
+const int DEFAULT_MIDI_PORT = 0;
+
+void MIDIManager::openDefaultPort() {
+ if (!_midiInput) {
+ _midiInput = new RtMidiIn();
+
+ if (_midiInput->getPortCount() > 0) {
+ qDebug() << "MIDIManager opening port" << DEFAULT_MIDI_PORT;
+
+ _midiInput->openPort(DEFAULT_MIDI_PORT);
+
+ // don't ignore sysex, timing, or active sensing messages
+ _midiInput->ignoreTypes(false, false, false);
+
+ _midiInput->setCallback(&MIDIManager::midiCallback);
+ } else {
+ qDebug() << "MIDIManager openDefaultPort called but there are no ports available.";
+ delete _midiInput;
+ _midiInput = NULL;
+ }
+ }
+}
\ No newline at end of file
diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h
new file mode 100644
index 0000000000..da41050216
--- /dev/null
+++ b/interface/src/devices/MIDIManager.h
@@ -0,0 +1,46 @@
+//
+// MIDIManager.h
+// interface/src/devices
+//
+// Created by Stephen Birarda on 2014-06-30.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_MIDIManager_h
+#define hifi_MIDIManager_h
+
+#include
+#include
+
+#include
+
+#include
+
+class MIDIManager : public QObject {
+ Q_OBJECT
+
+ Q_PROPERTY(unsigned int NoteOn READ NoteOn)
+ Q_PROPERTY(unsigned int NoteOff READ NoteOff)
+public:
+ static MIDIManager& getInstance();
+ static void midiCallback(double deltaTime, std::vector* message, void* userData);
+
+ ~MIDIManager();
+
+ void openDefaultPort();
+ bool hasDevice() const { return !!_midiInput; }
+public slots:
+ unsigned int NoteOn() const { return 144; }
+ unsigned int NoteOff() const { return 128; }
+signals:
+ void midiEvent(const MIDIEvent& event);
+
+private:
+ RtMidiIn* _midiInput;
+};
+
+
+#endif // hifi_MIDIManager_h
\ No newline at end of file
diff --git a/libraries/script-engine/src/MIDIEvent.cpp b/libraries/script-engine/src/MIDIEvent.cpp
new file mode 100644
index 0000000000..b32c5d9d87
--- /dev/null
+++ b/libraries/script-engine/src/MIDIEvent.cpp
@@ -0,0 +1,37 @@
+//
+// MIDIEvent.cpp
+// libraries/script-engine/src
+//
+// Created by Stephen Birarda on 2014-06-30.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "MIDIEvent.h"
+
+void registerMIDIMetaTypes(QScriptEngine* engine) {
+ qScriptRegisterMetaType(engine, midiEventToScriptValue, midiEventFromScriptValue);
+}
+
+const QString MIDI_DELTA_TIME_PROP_NAME = "deltaTime";
+const QString MIDI_EVENT_TYPE_PROP_NAME = "type";
+const QString MIDI_DATA_1_PROP_NAME = "data1";
+const QString MIDI_DATA_2_PROP_NAME = "data2";
+
+QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event) {
+ QScriptValue obj = engine->newObject();
+ obj.setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime);
+ obj.setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type);
+ obj.setProperty(MIDI_DATA_1_PROP_NAME, event.data1);
+ obj.setProperty(MIDI_DATA_2_PROP_NAME, event.data2);
+ return obj;
+}
+
+void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event) {
+ event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble();
+ event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt();
+ event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt();
+ event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt();
+}
\ No newline at end of file
diff --git a/libraries/script-engine/src/MIDIEvent.h b/libraries/script-engine/src/MIDIEvent.h
new file mode 100644
index 0000000000..6bf4a4b72b
--- /dev/null
+++ b/libraries/script-engine/src/MIDIEvent.h
@@ -0,0 +1,32 @@
+//
+// MIDIEvent.h
+// libraries/script-engine/src
+//
+// Created by Stephen Birarda on 2014-06-30.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include
+
+#ifndef hifi_MIDIEvent_h
+#define hifi_MIDIEvent_h
+
+class MIDIEvent {
+public:
+ double deltaTime;
+ unsigned int type;
+ unsigned int data1;
+ unsigned int data2;
+};
+
+Q_DECLARE_METATYPE(MIDIEvent)
+
+void registerMIDIMetaTypes(QScriptEngine* engine);
+
+QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event);
+void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event);
+
+#endif // hifi_MIDIEvent_h
\ No newline at end of file
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 350473cc87..630e585d07 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -33,6 +33,7 @@
#include "AnimationObject.h"
#include "MenuItemProperties.h"
+#include "MIDIEvent.h"
#include "LocalVoxels.h"
#include "ScriptEngine.h"
#include "XMLHttpRequestClass.h"
@@ -217,6 +218,7 @@ void ScriptEngine::init() {
// register various meta-types
registerMetaTypes(&_engine);
+ registerMIDIMetaTypes(&_engine);
registerVoxelMetaTypes(&_engine);
registerEventTypes(&_engine);
registerMenuItemProperties(&_engine);