initial pass of MIDI implementation that bubbles events to JS

This commit is contained in:
Stephen Birarda 2014-07-01 09:53:18 -07:00
parent 657bf6b3d5
commit 5ba4a4dbb5
10 changed files with 321 additions and 38 deletions

4
.gitignore vendored
View file

@ -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/

View file

@ -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 ()

View file

@ -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")

41
interface/external/rtmidi/readme.txt vendored Normal file
View file

@ -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<BR>
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.

View file

@ -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);

View file

@ -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 <QtCore/QDebug>
#include "MIDIManager.h"
MIDIManager& MIDIManager::getInstance() {
static MIDIManager sharedInstance;
return sharedInstance;
}
void MIDIManager::midiCallback(double deltaTime, std::vector<unsigned char>* 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;
}
}
}

View file

@ -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 <QtCore/QObject>
#include <QtScript/QScriptEngine>
#include <MIDIEvent.h>
#include <RtMidi.h>
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<unsigned char>* 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

View file

@ -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();
}

View file

@ -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 <QtScript/QScriptEngine>
#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

View file

@ -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);