From 3004ee08e1c311eaebf56a5bcbf3364079b80d1d Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Thu, 18 Jan 2018 21:18:36 -0800 Subject: [PATCH 1/8] Fix lockup when no midi devices present. --- libraries/midi/src/Midi.cpp | 818 ++++++++++++++++++------------------ 1 file changed, 409 insertions(+), 409 deletions(-) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 69c35c4a20..680e53a8c7 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -1,409 +1,409 @@ -// -// Midi.cpp -// libraries/midi/src -// -// Created by Burt Sloane -// Modified by Bruce Brown -// Copyright 2015 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 "Midi.h" - - -#include - -#if defined Q_OS_WIN32 -#include "Windows.h" -#endif - -#if defined Q_OS_WIN32 -const int MIDI_BYTE_MASK = 0x0FF; -const int MIDI_NIBBLE_MASK = 0x00F; -const int MIDI_PITCH_BEND_MASK = 0x3F80; -const int MIDI_SHIFT_STATUS = 4; -const int MIDI_SHIFT_NOTE = 8; -const int MIDI_SHIFT_VELOCITY = 16; -const int MIDI_SHIFT_PITCH_BEND = 9; -// Status Decode -const int MIDI_NOTE_OFF = 0x8; -const int MIDI_NOTE_ON = 0x9; -const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; -const int MIDI_PROGRAM_CHANGE = 0xc; -const int MIDI_CHANNEL_PRESSURE = 0xd; -const int MIDI_PITCH_BEND_CHANGE = 0xe; -const int MIDI_SYSTEM_MESSAGE = 0xf; -#endif - -const int MIDI_CONTROL_CHANGE = 0xb; -const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; - -static Midi* instance = NULL; // communicate this to non-class callbacks -static bool thruModeEnabled = false; -static bool broadcastEnabled = false; -static bool typeNoteOffEnabled = true; -static bool typeNoteOnEnabled = true; -static bool typePolyKeyPressureEnabled = false; -static bool typeControlChangeEnabled = true; -static bool typeProgramChangeEnabled = true; -static bool typeChanPressureEnabled = false; -static bool typePitchBendEnabled = true; -static bool typeSystemMessageEnabled = false; - -std::vector Midi::midiInExclude; -std::vector Midi::midiOutExclude; - -#if defined Q_OS_WIN32 - -#pragma comment(lib, "Winmm.lib") - -// -std::vector midihin; -std::vector midihout; - -void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MIM_OPEN: - // message not used - break; - case MIM_CLOSE: - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - midihin[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - case MIM_DATA: { - int device = -1; - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - device = i; - } - } - int raw = dwParam1; - int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; - int status = MIDI_BYTE_MASK & dwParam1; - int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); - int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); - int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); - int bend = 0; - int program = 0; - if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { - return; - } - if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { - return; - } - if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { - return; - } - if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { - return; - } - if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { - program = note; - note = 0; - } - if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { - velocity = note; - note = 0; - } - if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { - bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | - (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; - channel = 0; // Weird values on different instruments - note = 0; - velocity = 0; - } - if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { - return; - } - if (thruModeEnabled) { - instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. - } - instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript - break; - } - } -} - -void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MOM_OPEN: - // message not used - break; - case MOM_CLOSE: - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] == hmo) { - midihout[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - } -} - -void Midi::sendRawMessage(int device, int raw) { - if (broadcastEnabled) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], raw); - } - } - } else { - midiOutShortMsg(midihout[device], raw); - } -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { - int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); - if (broadcastEnabled) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } - } - } else { - midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } -} - -void Midi::sendNote(int status, int note, int velocity) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); - } - } -} - -void Midi::MidiSetup() { - midihin.clear(); - midihout.clear(); - - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiInExclude.size(); j++) { - if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN INPUT BY NAME - HMIDIIN tmphin; - midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); - midiInStart(tmphin); - midihin.push_back(tmphin); - } - } - - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiOutExclude.size(); j++) { - if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN OUTPUT BY NAME - HMIDIOUT tmphout; - midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); - midihout.push_back(tmphout); - } - } - - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); - - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] != NULL) { - midiInStop(midihin[i]); - midiInClose(midihin[i]); - } - } - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutClose(midihout[i]); - } - } - midihin.clear(); - midihout.clear(); -} -#else -void Midi::sendRawMessage(int device, int raw) { -} - -void Midi::sendNote(int status, int note, int velocity) { -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ -} - -void Midi::MidiSetup() { - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); -} -#endif - -void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { - QVariantMap eventData; - eventData["device"] = device; - eventData["raw"] = raw; - eventData["channel"] = channel; - eventData["status"] = status; - eventData["type"] = type; - eventData["note"] = note; - eventData["velocity"] = velocity; - eventData["bend"] = bend; - eventData["program"] = program; - emit midiNote(eventData);// Legacy - emit midiMessage(eventData); -} - -void Midi::midiHardwareChange() { - emit midiReset(); -} -// - -Midi::Midi() { - instance = this; -#if defined Q_OS_WIN32 - midiOutExclude.push_back("Microsoft GS Wavetable Synth"); // we don't want to hear this thing (Lags) -#endif - MidiSetup(); -} - -Midi::~Midi() { -} - -void Midi::sendRawDword(int device, int raw) { - sendRawMessage(device, raw); -} - -void Midi::playMidiNote(int status, int note, int velocity) { - sendNote(status, note, velocity); -} - -void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { - sendMessage(device, channel, type, note, velocity); -} - -void Midi::allNotesOff() { - sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off -} - -void Midi::resetDevices() { - MidiCleanup(); - MidiSetup(); -} - -void Midi::USBchanged() { - instance->MidiCleanup(); - instance->MidiSetup(); - instance->midiHardwareChange(); -} - -// - -QStringList Midi::listMidiDevices(bool output) { - QStringList rv; -#if defined Q_OS_WIN32 - if (output) { - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - rv.append(outcaps.szPname); - } - } else { - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - rv.append(incaps.szPname); - } - } -#endif - return rv; -} - -void Midi::unblockMidiDevice(QString name, bool output) { - if (output) { - for (unsigned long i = 0; i < midiOutExclude.size(); i++) { - if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiOutExclude.erase(midiOutExclude.begin() + i); - break; - } - } - } else { - for (unsigned long i = 0; i < midiInExclude.size(); i++) { - if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiInExclude.erase(midiInExclude.begin() + i); - break; - } - } - } -} - -void Midi::blockMidiDevice(QString name, bool output) { - unblockMidiDevice(name, output); // make sure it's only in there once - if (output) { - midiOutExclude.push_back(name); - } else { - midiInExclude.push_back(name); - } -} - -void Midi::thruModeEnable(bool enable) { - thruModeEnabled = enable; -} - -void Midi::broadcastEnable(bool enable) { - broadcastEnabled = enable; -} - -void Midi::typeNoteOffEnable(bool enable) { - typeNoteOffEnabled = enable; -} - -void Midi::typeNoteOnEnable(bool enable) { - typeNoteOnEnabled = enable; -} - -void Midi::typePolyKeyPressureEnable(bool enable) { - typePolyKeyPressureEnabled = enable; -} - -void Midi::typeControlChangeEnable(bool enable) { - typeControlChangeEnabled = enable; -} - -void Midi::typeProgramChangeEnable(bool enable) { - typeProgramChangeEnabled = enable; -} - -void Midi::typeChanPressureEnable(bool enable) { - typeChanPressureEnabled = enable; -} - -void Midi::typePitchBendEnable(bool enable) { - typePitchBendEnabled = enable; -} - -void Midi::typeSystemMessageEnable(bool enable) { - typeSystemMessageEnabled = enable; -} +// +// Midi.cpp +// libraries/midi/src +// +// Created by Burt Sloane +// Modified by Bruce Brown +// Copyright 2015 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 "Midi.h" + + +#include + +#if defined Q_OS_WIN32 +#include "Windows.h" +#endif + +#if defined Q_OS_WIN32 +const int MIDI_BYTE_MASK = 0x0FF; +const int MIDI_NIBBLE_MASK = 0x00F; +const int MIDI_PITCH_BEND_MASK = 0x3F80; +const int MIDI_SHIFT_STATUS = 4; +const int MIDI_SHIFT_NOTE = 8; +const int MIDI_SHIFT_VELOCITY = 16; +const int MIDI_SHIFT_PITCH_BEND = 9; +// Status Decode +const int MIDI_NOTE_OFF = 0x8; +const int MIDI_NOTE_ON = 0x9; +const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; +const int MIDI_PROGRAM_CHANGE = 0xc; +const int MIDI_CHANNEL_PRESSURE = 0xd; +const int MIDI_PITCH_BEND_CHANGE = 0xe; +const int MIDI_SYSTEM_MESSAGE = 0xf; +#endif + +const int MIDI_CONTROL_CHANGE = 0xb; +const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; + +static Midi* instance = NULL; // communicate this to non-class callbacks +static bool thruModeEnabled = false; +static bool broadcastEnabled = false; +static bool typeNoteOffEnabled = true; +static bool typeNoteOnEnabled = true; +static bool typePolyKeyPressureEnabled = false; +static bool typeControlChangeEnabled = true; +static bool typeProgramChangeEnabled = true; +static bool typeChanPressureEnabled = false; +static bool typePitchBendEnabled = true; +static bool typeSystemMessageEnabled = false; + +std::vector Midi::midiInExclude; +std::vector Midi::midiOutExclude; + +#if defined Q_OS_WIN32 + +#pragma comment(lib, "Winmm.lib") + +// +std::vector midihin; +std::vector midihout; + +void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MIM_OPEN: + // message not used + break; + case MIM_CLOSE: + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + midihin[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + case MIM_DATA: { + int device = -1; + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + device = i; + } + } + int raw = dwParam1; + int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; + int status = MIDI_BYTE_MASK & dwParam1; + int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); + int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); + int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); + int bend = 0; + int program = 0; + if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { + return; + } + if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { + return; + } + if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { + return; + } + if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { + return; + } + if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { + program = note; + note = 0; + } + if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { + velocity = note; + note = 0; + } + if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { + bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | + (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; + channel = 0; // Weird values on different instruments + note = 0; + velocity = 0; + } + if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { + return; + } + if (thruModeEnabled) { + instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. + } + instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript + break; + } + } +} + +void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MOM_OPEN: + // message not used + break; + case MOM_CLOSE: + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] == hmo) { + midihout[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + } +} + +void Midi::sendRawMessage(int device, int raw) { + if (broadcastEnabled) { + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], raw); + } + } + } else { + midiOutShortMsg(midihout[device], raw); + } +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { + int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); + if (broadcastEnabled) { + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } + } + } else { + midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } +} + +void Midi::sendNote(int status, int note, int velocity) { + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); + } + } +} + +void Midi::MidiSetup() { + midihin.clear(); + midihout.clear(); + + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiInExclude.size(); j++) { + if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN INPUT BY NAME + HMIDIIN tmphin; + midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); + midiInStart(tmphin); + midihin.push_back(tmphin); + } + } + + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiOutExclude.size(); j++) { + if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN OUTPUT BY NAME + HMIDIOUT tmphout; + midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); + midihout.push_back(tmphout); + } + } + + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); + + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] != NULL) { + midiInStop(midihin[i]); + midiInClose(midihin[i]); + } + } + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutClose(midihout[i]); + } + } + midihin.clear(); + midihout.clear(); +} +#else +void Midi::sendRawMessage(int device, int raw) { +} + +void Midi::sendNote(int status, int note, int velocity) { +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ +} + +void Midi::MidiSetup() { + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); +} +#endif + +void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { + QVariantMap eventData; + eventData["device"] = device; + eventData["raw"] = raw; + eventData["channel"] = channel; + eventData["status"] = status; + eventData["type"] = type; + eventData["note"] = note; + eventData["velocity"] = velocity; + eventData["bend"] = bend; + eventData["program"] = program; + emit midiNote(eventData);// Legacy + emit midiMessage(eventData); +} + +void Midi::midiHardwareChange() { + emit midiReset(); +} +// + +Midi::Midi() { + instance = this; +#if defined Q_OS_WIN32 + midiOutExclude.push_back("Microsoft GS Wavetable Synth"); // we don't want to hear this thing (Lags) +#endif + MidiSetup(); +} + +Midi::~Midi() { +} + +void Midi::sendRawDword(int device, int raw) { + sendRawMessage(device, raw); +} + +void Midi::playMidiNote(int status, int note, int velocity) { + sendNote(status, note, velocity); +} + +void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { + sendMessage(device, channel, type, note, velocity); +} + +void Midi::allNotesOff() { + sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off +} + +void Midi::resetDevices() { + MidiCleanup(); + MidiSetup(); +} + +void Midi::USBchanged() { + instance->MidiCleanup(); + instance->MidiSetup(); + instance->midiHardwareChange(); +} + +// + +QStringList Midi::listMidiDevices(bool output) { + QStringList rv; +#if defined Q_OS_WIN32 + if (output) { + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + rv.append(outcaps.szPname); + } + } else { + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + rv.append(incaps.szPname); + } + } +#endif + return rv; +} + +void Midi::unblockMidiDevice(QString name, bool output) { + if (output) { + for (unsigned long i = 0; i < midiOutExclude.size(); i++) { + if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiOutExclude.erase(midiOutExclude.begin() + i); + break; + } + } + } else { + for (unsigned long i = 0; i < midiInExclude.size(); i++) { + if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiInExclude.erase(midiInExclude.begin() + i); + break; + } + } + } +} + +void Midi::blockMidiDevice(QString name, bool output) { + unblockMidiDevice(name, output); // make sure it's only in there once + if (output) { + midiOutExclude.push_back(name); + } else { + midiInExclude.push_back(name); + } +} + +void Midi::thruModeEnable(bool enable) { + thruModeEnabled = enable; +} + +void Midi::broadcastEnable(bool enable) { + broadcastEnabled = enable; +} + +void Midi::typeNoteOffEnable(bool enable) { + typeNoteOffEnabled = enable; +} + +void Midi::typeNoteOnEnable(bool enable) { + typeNoteOnEnabled = enable; +} + +void Midi::typePolyKeyPressureEnable(bool enable) { + typePolyKeyPressureEnabled = enable; +} + +void Midi::typeControlChangeEnable(bool enable) { + typeControlChangeEnabled = enable; +} + +void Midi::typeProgramChangeEnable(bool enable) { + typeProgramChangeEnabled = enable; +} + +void Midi::typeChanPressureEnable(bool enable) { + typeChanPressureEnabled = enable; +} + +void Midi::typePitchBendEnable(bool enable) { + typePitchBendEnabled = enable; +} + +void Midi::typeSystemMessageEnable(bool enable) { + typeSystemMessageEnabled = enable; +} From bb09c71bda983d59cf5073b6ef31614a831369bf Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Thu, 18 Jan 2018 21:35:01 -0800 Subject: [PATCH 2/8] Fix crash caused by no midi device present --- Midi.cpp | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Midi.h | 108 +++++++++++++++ 2 files changed, 514 insertions(+) create mode 100644 Midi.cpp create mode 100644 Midi.h diff --git a/Midi.cpp b/Midi.cpp new file mode 100644 index 0000000000..ec13508805 --- /dev/null +++ b/Midi.cpp @@ -0,0 +1,406 @@ +// +// Midi.cpp +// libraries/midi/src +// +// Created by Burt Sloane +// Modified by Bruce Brown +// Copyright 2015 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 "Midi.h" + + +#include + +#if defined Q_OS_WIN32 +#include "Windows.h" +#endif + +#if defined Q_OS_WIN32 +const int MIDI_BYTE_MASK = 0x0FF; +const int MIDI_NIBBLE_MASK = 0x00F; +const int MIDI_PITCH_BEND_MASK = 0x3F80; +const int MIDI_SHIFT_STATUS = 4; +const int MIDI_SHIFT_NOTE = 8; +const int MIDI_SHIFT_VELOCITY = 16; +const int MIDI_SHIFT_PITCH_BEND = 9; +// Status Decode +const int MIDI_NOTE_OFF = 0x8; +const int MIDI_NOTE_ON = 0x9; +const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; +const int MIDI_PROGRAM_CHANGE = 0xc; +const int MIDI_CHANNEL_PRESSURE = 0xd; +const int MIDI_PITCH_BEND_CHANGE = 0xe; +const int MIDI_SYSTEM_MESSAGE = 0xf; +#endif + +const int MIDI_CONTROL_CHANGE = 0xb; +const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; + +static Midi* instance = NULL; // communicate this to non-class callbacks +static bool thruModeEnabled = false; +static bool broadcastEnabled = false; +static bool typeNoteOffEnabled = true; +static bool typeNoteOnEnabled = true; +static bool typePolyKeyPressureEnabled = false; +static bool typeControlChangeEnabled = true; +static bool typeProgramChangeEnabled = true; +static bool typeChanPressureEnabled = false; +static bool typePitchBendEnabled = true; +static bool typeSystemMessageEnabled = false; + +std::vector Midi::midiInExclude; +std::vector Midi::midiOutExclude; + +#if defined Q_OS_WIN32 + +#pragma comment(lib, "Winmm.lib") + +// +std::vector midihin; +std::vector midihout; + +void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MIM_OPEN: + // message not used + break; + case MIM_CLOSE: + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + midihin[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + case MIM_DATA: { + int device = -1; + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + device = i; + } + } + int raw = dwParam1; + int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; + int status = MIDI_BYTE_MASK & dwParam1; + int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); + int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); + int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); + int bend = 0; + int program = 0; + if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { + return; + } + if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { + return; + } + if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { + return; + } + if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { + return; + } + if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { + program = note; + note = 0; + } + if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { + velocity = note; + note = 0; + } + if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { + bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | + (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; + channel = 0; // Weird values on different instruments + note = 0; + velocity = 0; + } + if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { + return; + } + if (thruModeEnabled) { + instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. + } + instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript + break; + } + } +} + +void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MOM_OPEN: + // message not used + break; + case MOM_CLOSE: + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] == hmo) { + midihout[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + } +} + +void Midi::sendRawMessage(int device, int raw) { + if (broadcastEnabled) { + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], raw); + } + } + } else { + midiOutShortMsg(midihout[device], raw); + } +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { + int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); + if (broadcastEnabled) { + for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } + } + } else { + midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } +} + +void Midi::sendNote(int status, int note, int velocity) { + for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); + } + } +} + +void Midi::MidiSetup() { + midihin.clear(); + midihout.clear(); + + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiInExclude.size(); j++) { + if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN INPUT BY NAME + HMIDIIN tmphin; + midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); + midiInStart(tmphin); + midihin.push_back(tmphin); + } + } + + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiOutExclude.size(); j++) { + if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN OUTPUT BY NAME + HMIDIOUT tmphout; + midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); + midihout.push_back(tmphout); + } + } + + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); + + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] != NULL) { + midiInStop(midihin[i]); + midiInClose(midihin[i]); + } + } + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutClose(midihout[i]); + } + } + midihin.clear(); + midihout.clear(); +} +#else +void Midi::sendRawMessage(int device, int raw) { +} + +void Midi::sendNote(int status, int note, int velocity) { +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ +} + +void Midi::MidiSetup() { + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); +} +#endif + +void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { + QVariantMap eventData; + eventData["device"] = device; + eventData["raw"] = raw; + eventData["channel"] = channel; + eventData["status"] = status; + eventData["type"] = type; + eventData["note"] = note; + eventData["velocity"] = velocity; + eventData["bend"] = bend; + eventData["program"] = program; + emit midiNote(eventData);// Legacy + emit midiMessage(eventData); +} + +void Midi::midiHardwareChange() { + emit midiReset(); +} +// + +Midi::Midi() { + instance = this; + MidiSetup(); +} + +Midi::~Midi() { +} + +void Midi::sendRawDword(int device, int raw) { + sendRawMessage(device, raw); +} + +void Midi::playMidiNote(int status, int note, int velocity) { + sendNote(status, note, velocity); +} + +void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { + sendMessage(device, channel, type, note, velocity); +} + +void Midi::allNotesOff() { + sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off +} + +void Midi::resetDevices() { + MidiCleanup(); + MidiSetup(); +} + +void Midi::USBchanged() { + instance->MidiCleanup(); + instance->MidiSetup(); + instance->midiHardwareChange(); +} + +// + +QStringList Midi::listMidiDevices(bool output) { + QStringList rv; +#if defined Q_OS_WIN32 + if (output) { + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + rv.append(outcaps.szPname); + } + } else { + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + rv.append(incaps.szPname); + } + } +#endif + return rv; +} + +void Midi::unblockMidiDevice(QString name, bool output) { + if (output) { + for (unsigned long i = 0; i < midiOutExclude.size(); i++) { + if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiOutExclude.erase(midiOutExclude.begin() + i); + break; + } + } + } else { + for (unsigned long i = 0; i < midiInExclude.size(); i++) { + if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiInExclude.erase(midiInExclude.begin() + i); + break; + } + } + } +} + +void Midi::blockMidiDevice(QString name, bool output) { + unblockMidiDevice(name, output); // make sure it's only in there once + if (output) { + midiOutExclude.push_back(name); + } else { + midiInExclude.push_back(name); + } +} + +void Midi::thruModeEnable(bool enable) { + thruModeEnabled = enable; +} + +void Midi::broadcastEnable(bool enable) { + broadcastEnabled = enable; +} + +void Midi::typeNoteOffEnable(bool enable) { + typeNoteOffEnabled = enable; +} + +void Midi::typeNoteOnEnable(bool enable) { + typeNoteOnEnabled = enable; +} + +void Midi::typePolyKeyPressureEnable(bool enable) { + typePolyKeyPressureEnabled = enable; +} + +void Midi::typeControlChangeEnable(bool enable) { + typeControlChangeEnabled = enable; +} + +void Midi::typeProgramChangeEnable(bool enable) { + typeProgramChangeEnabled = enable; +} + +void Midi::typeChanPressureEnable(bool enable) { + typeChanPressureEnabled = enable; +} + +void Midi::typePitchBendEnable(bool enable) { + typePitchBendEnabled = enable; +} + +void Midi::typeSystemMessageEnable(bool enable) { + typeSystemMessageEnabled = enable; +} diff --git a/Midi.h b/Midi.h new file mode 100644 index 0000000000..f7940bbe5d --- /dev/null +++ b/Midi.h @@ -0,0 +1,108 @@ +// +// Midi.h +// libraries/midi/src +// +// Created by Burt Sloane +// Modified by Bruce Brown +// Copyright 2015 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_Midi_h +#define hifi_Midi_h + +#include +#include +#include + +#include +#include + +class Midi : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + void midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program); // relay a note to Javascript + void midiHardwareChange(); // relay hardware change to Javascript + void sendRawMessage(int device, int raw); // relay midi message to MIDI outputs + void sendNote(int status, int note, int velocity); // relay a note to MIDI outputs + void sendMessage(int device, int channel, int type, int note, int velocity); // relay a message to MIDI outputs + static void USBchanged(); + +private: + static std::vector midiInExclude; + static std::vector midiOutExclude; + +private: + void MidiSetup(); + void MidiCleanup(); + +signals: + void midiNote(QVariantMap eventData); + void midiMessage(QVariantMap eventData); + void midiReset(); + + public slots: + // Send Raw Midi Packet to all connected devices + Q_INVOKABLE void sendRawDword(int device, int raw); + /// Send Raw Midi message to selected device + /// @param {int} device: device number + /// @param {int} raw: raw midi message (DWORD) + + // Send Midi Message to all connected devices + Q_INVOKABLE void sendMidiMessage(int device, int channel, int type, int note, int velocity); + /// Send midi message to selected device/devices + /// @param {int} device: device number + /// @param {int} channel: channel number + /// @param {int} type: 0x8 is noteoff, 0x9 is noteon (if velocity=0, noteoff), etc + /// @param {int} note: midi note number + /// @param {int} velocity: note velocity (0 means noteoff) + + // Send Midi Message to all connected devices + Q_INVOKABLE void playMidiNote(int status, int note, int velocity); + /// play a note on all connected devices + /// @param {int} status: 0x80 is noteoff, 0x90 is noteon (if velocity=0, noteoff), etc + /// @param {int} note: midi note number + /// @param {int} velocity: note velocity (0 means noteoff) + + /// turn off all notes on all connected devices + Q_INVOKABLE void allNotesOff(); + + /// clean up and re-discover attached devices + Q_INVOKABLE void resetDevices(); + + /// ask for a list of inputs/outputs + Q_INVOKABLE QStringList listMidiDevices(bool output); + + /// block an input/output by name + Q_INVOKABLE void blockMidiDevice(QString name, bool output); + + /// unblock an input/output by name + Q_INVOKABLE void unblockMidiDevice(QString name, bool output); + + /// repeat all incoming notes to all outputs (default disabled) + Q_INVOKABLE void thruModeEnable(bool enable); + + /// broadcast on all unblocked devices + Q_INVOKABLE void broadcastEnable(bool enable); + + /// filter by event types + Q_INVOKABLE void typeNoteOffEnable(bool enable); + Q_INVOKABLE void typeNoteOnEnable(bool enable); + Q_INVOKABLE void typePolyKeyPressureEnable(bool enable); + Q_INVOKABLE void typeControlChangeEnable(bool enable); + Q_INVOKABLE void typeProgramChangeEnable(bool enable); + Q_INVOKABLE void typeChanPressureEnable(bool enable); + Q_INVOKABLE void typePitchBendEnable(bool enable); + Q_INVOKABLE void typeSystemMessageEnable(bool enable); + + +public: + Midi(); + virtual ~Midi(); +}; + +#endif // hifi_Midi_h From 39e938ccc7add8d1a5debca2c06e9bce37f36686 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Fri, 19 Jan 2018 11:52:09 -0800 Subject: [PATCH 3/8] Removed Tabs & CR/LF --- libraries/midi/src/Midi.cpp | 815 ++++++++++++++++++------------------ 1 file changed, 406 insertions(+), 409 deletions(-) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 680e53a8c7..7f086340ba 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -1,409 +1,406 @@ -// -// Midi.cpp -// libraries/midi/src -// -// Created by Burt Sloane -// Modified by Bruce Brown -// Copyright 2015 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 "Midi.h" - - -#include - -#if defined Q_OS_WIN32 -#include "Windows.h" -#endif - -#if defined Q_OS_WIN32 -const int MIDI_BYTE_MASK = 0x0FF; -const int MIDI_NIBBLE_MASK = 0x00F; -const int MIDI_PITCH_BEND_MASK = 0x3F80; -const int MIDI_SHIFT_STATUS = 4; -const int MIDI_SHIFT_NOTE = 8; -const int MIDI_SHIFT_VELOCITY = 16; -const int MIDI_SHIFT_PITCH_BEND = 9; -// Status Decode -const int MIDI_NOTE_OFF = 0x8; -const int MIDI_NOTE_ON = 0x9; -const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; -const int MIDI_PROGRAM_CHANGE = 0xc; -const int MIDI_CHANNEL_PRESSURE = 0xd; -const int MIDI_PITCH_BEND_CHANGE = 0xe; -const int MIDI_SYSTEM_MESSAGE = 0xf; -#endif - -const int MIDI_CONTROL_CHANGE = 0xb; -const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; - -static Midi* instance = NULL; // communicate this to non-class callbacks -static bool thruModeEnabled = false; -static bool broadcastEnabled = false; -static bool typeNoteOffEnabled = true; -static bool typeNoteOnEnabled = true; -static bool typePolyKeyPressureEnabled = false; -static bool typeControlChangeEnabled = true; -static bool typeProgramChangeEnabled = true; -static bool typeChanPressureEnabled = false; -static bool typePitchBendEnabled = true; -static bool typeSystemMessageEnabled = false; - -std::vector Midi::midiInExclude; -std::vector Midi::midiOutExclude; - -#if defined Q_OS_WIN32 - -#pragma comment(lib, "Winmm.lib") - -// -std::vector midihin; -std::vector midihout; - -void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MIM_OPEN: - // message not used - break; - case MIM_CLOSE: - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - midihin[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - case MIM_DATA: { - int device = -1; - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - device = i; - } - } - int raw = dwParam1; - int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; - int status = MIDI_BYTE_MASK & dwParam1; - int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); - int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); - int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); - int bend = 0; - int program = 0; - if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { - return; - } - if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { - return; - } - if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { - return; - } - if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { - return; - } - if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { - program = note; - note = 0; - } - if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { - velocity = note; - note = 0; - } - if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { - bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | - (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; - channel = 0; // Weird values on different instruments - note = 0; - velocity = 0; - } - if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { - return; - } - if (thruModeEnabled) { - instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. - } - instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript - break; - } - } -} - -void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MOM_OPEN: - // message not used - break; - case MOM_CLOSE: - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] == hmo) { - midihout[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - } -} - -void Midi::sendRawMessage(int device, int raw) { - if (broadcastEnabled) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], raw); - } - } - } else { - midiOutShortMsg(midihout[device], raw); - } -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { - int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); - if (broadcastEnabled) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } - } - } else { - midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } -} - -void Midi::sendNote(int status, int note, int velocity) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); - } - } -} - -void Midi::MidiSetup() { - midihin.clear(); - midihout.clear(); - - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiInExclude.size(); j++) { - if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN INPUT BY NAME - HMIDIIN tmphin; - midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); - midiInStart(tmphin); - midihin.push_back(tmphin); - } - } - - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiOutExclude.size(); j++) { - if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN OUTPUT BY NAME - HMIDIOUT tmphout; - midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); - midihout.push_back(tmphout); - } - } - - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); - - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] != NULL) { - midiInStop(midihin[i]); - midiInClose(midihin[i]); - } - } - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutClose(midihout[i]); - } - } - midihin.clear(); - midihout.clear(); -} -#else -void Midi::sendRawMessage(int device, int raw) { -} - -void Midi::sendNote(int status, int note, int velocity) { -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ -} - -void Midi::MidiSetup() { - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); -} -#endif - -void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { - QVariantMap eventData; - eventData["device"] = device; - eventData["raw"] = raw; - eventData["channel"] = channel; - eventData["status"] = status; - eventData["type"] = type; - eventData["note"] = note; - eventData["velocity"] = velocity; - eventData["bend"] = bend; - eventData["program"] = program; - emit midiNote(eventData);// Legacy - emit midiMessage(eventData); -} - -void Midi::midiHardwareChange() { - emit midiReset(); -} -// - -Midi::Midi() { - instance = this; -#if defined Q_OS_WIN32 - midiOutExclude.push_back("Microsoft GS Wavetable Synth"); // we don't want to hear this thing (Lags) -#endif - MidiSetup(); -} - -Midi::~Midi() { -} - -void Midi::sendRawDword(int device, int raw) { - sendRawMessage(device, raw); -} - -void Midi::playMidiNote(int status, int note, int velocity) { - sendNote(status, note, velocity); -} - -void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { - sendMessage(device, channel, type, note, velocity); -} - -void Midi::allNotesOff() { - sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off -} - -void Midi::resetDevices() { - MidiCleanup(); - MidiSetup(); -} - -void Midi::USBchanged() { - instance->MidiCleanup(); - instance->MidiSetup(); - instance->midiHardwareChange(); -} - -// - -QStringList Midi::listMidiDevices(bool output) { - QStringList rv; -#if defined Q_OS_WIN32 - if (output) { - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - rv.append(outcaps.szPname); - } - } else { - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - rv.append(incaps.szPname); - } - } -#endif - return rv; -} - -void Midi::unblockMidiDevice(QString name, bool output) { - if (output) { - for (unsigned long i = 0; i < midiOutExclude.size(); i++) { - if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiOutExclude.erase(midiOutExclude.begin() + i); - break; - } - } - } else { - for (unsigned long i = 0; i < midiInExclude.size(); i++) { - if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiInExclude.erase(midiInExclude.begin() + i); - break; - } - } - } -} - -void Midi::blockMidiDevice(QString name, bool output) { - unblockMidiDevice(name, output); // make sure it's only in there once - if (output) { - midiOutExclude.push_back(name); - } else { - midiInExclude.push_back(name); - } -} - -void Midi::thruModeEnable(bool enable) { - thruModeEnabled = enable; -} - -void Midi::broadcastEnable(bool enable) { - broadcastEnabled = enable; -} - -void Midi::typeNoteOffEnable(bool enable) { - typeNoteOffEnabled = enable; -} - -void Midi::typeNoteOnEnable(bool enable) { - typeNoteOnEnabled = enable; -} - -void Midi::typePolyKeyPressureEnable(bool enable) { - typePolyKeyPressureEnabled = enable; -} - -void Midi::typeControlChangeEnable(bool enable) { - typeControlChangeEnabled = enable; -} - -void Midi::typeProgramChangeEnable(bool enable) { - typeProgramChangeEnabled = enable; -} - -void Midi::typeChanPressureEnable(bool enable) { - typeChanPressureEnabled = enable; -} - -void Midi::typePitchBendEnable(bool enable) { - typePitchBendEnabled = enable; -} - -void Midi::typeSystemMessageEnable(bool enable) { - typeSystemMessageEnabled = enable; -} +// +// Midi.cpp +// libraries/midi/src +// +// Created by Burt Sloane +// Modified by Bruce Brown +// Copyright 2015 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 "Midi.h" + + +#include + +#if defined Q_OS_WIN32 +#include "Windows.h" +#endif + +#if defined Q_OS_WIN32 +const int MIDI_BYTE_MASK = 0x0FF; +const int MIDI_NIBBLE_MASK = 0x00F; +const int MIDI_PITCH_BEND_MASK = 0x3F80; +const int MIDI_SHIFT_STATUS = 4; +const int MIDI_SHIFT_NOTE = 8;- +const int MIDI_SHIFT_VELOCITY = 16; +const int MIDI_SHIFT_PITCH_BEND = 9; +// Status Decode +const int MIDI_NOTE_OFF = 0x8; +const int MIDI_NOTE_ON = 0x9; +const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; +const int MIDI_PROGRAM_CHANGE = 0xc; +const int MIDI_CHANNEL_PRESSURE = 0xd; +const int MIDI_PITCH_BEND_CHANGE = 0xe; +const int MIDI_SYSTEM_MESSAGE = 0xf; +#endif + +const int MIDI_CONTROL_CHANGE = 0xb; +const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; + +static Midi* instance = NULL; // communicate this to non-class callbacks +static bool thruModeEnabled = false; +static bool broadcastEnabled = false; +static bool typeNoteOffEnabled = true; +static bool typeNoteOnEnabled = true; +static bool typePolyKeyPressureEnabled = false; +static bool typeControlChangeEnabled = true; +static bool typeProgramChangeEnabled = true; +static bool typeChanPressureEnabled = false; +static bool typePitchBendEnabled = true; +static bool typeSystemMessageEnabled = false; + +std::vector Midi::midiInExclude; +std::vector Midi::midiOutExclude; + +#if defined Q_OS_WIN32 + +#pragma comment(lib, "Winmm.lib") + +// +std::vector midihin; +std::vector midihout; + +void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MIM_OPEN: + // message not used + break; + case MIM_CLOSE: + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + midihin[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + case MIM_DATA: { + int device = -1; + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] == hMidiIn) { + device = i; + } + } + int raw = dwParam1; + int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; + int status = MIDI_BYTE_MASK & dwParam1; + int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); + int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); + int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); + int bend = 0; + int program = 0; + if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { + return; + } + if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { + return; + } + if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { + return; + } + if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { + return; + } + if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { + program = note; + note = 0; + } + if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { + velocity = note; + note = 0; + } + if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { + bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | + (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; + channel = 0; // Weird values on different instruments + note = 0; + velocity = 0; + } + if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { + return; + } + if (thruModeEnabled) { + instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. + } + instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript + break; + } + } +} + +void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + switch (wMsg) { + case MOM_OPEN: + // message not used + break; + case MOM_CLOSE: + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] == hmo) { + midihout[i] = NULL; + instance->allNotesOff(); + instance->midiHardwareChange(); + } + } + break; + } +} + +void Midi::sendRawMessage(int device, int raw) { + if (broadcastEnabled) { + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], raw); + } + } + } else { + midiOutShortMsg(midihout[device], raw); + } +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { + int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); + if (broadcastEnabled) { + for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } + } + } else { + midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); + } +} + +void Midi::sendNote(int status, int note, int velocity) { + for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) + if (midihout[i] != NULL) { + midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); + } + } +} + +void Midi::MidiSetup() { + midihin.clear(); + midihout.clear(); + + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiInExclude.size(); j++) { + if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN INPUT BY NAME + HMIDIIN tmphin; + midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); + midiInStart(tmphin); + midihin.push_back(tmphin); + } + } + + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + + bool found = false; + for (int j = 0; j < midiOutExclude.size(); j++) { + if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { + found = true; + break; + } + } + if (!found) { // EXCLUDE AN OUTPUT BY NAME + HMIDIOUT tmphout; + midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); + midihout.push_back(tmphout); + } + } + + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); + + for (int i = 0; i < midihin.size(); i++) { + if (midihin[i] != NULL) { + midiInStop(midihin[i]); + midiInClose(midihin[i]); + } + } + for (int i = 0; i < midihout.size(); i++) { + if (midihout[i] != NULL) { + midiOutClose(midihout[i]); + } + } + midihin.clear(); + midihout.clear(); +} +#else +void Midi::sendRawMessage(int device, int raw) { +} + +void Midi::sendNote(int status, int note, int velocity) { +} + +void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ +} + +void Midi::MidiSetup() { + allNotesOff(); +} + +void Midi::MidiCleanup() { + allNotesOff(); +} +#endif + +void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { + QVariantMap eventData; + eventData["device"] = device; + eventData["raw"] = raw; + eventData["channel"] = channel; + eventData["status"] = status; + eventData["type"] = type; + eventData["note"] = note; + eventData["velocity"] = velocity; + eventData["bend"] = bend; + eventData["program"] = program; + emit midiNote(eventData);// Legacy + emit midiMessage(eventData); +} + +void Midi::midiHardwareChange() { + emit midiReset(); +} +// + +Midi::Midi() { + instance = this; + MidiSetup(); +} + +Midi::~Midi() { +} + +void Midi::sendRawDword(int device, int raw) { + sendRawMessage(device, raw); +} + +void Midi::playMidiNote(int status, int note, int velocity) { + sendNote(status, note, velocity); +} + +void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { + sendMessage(device, channel, type, note, velocity); +} + +void Midi::allNotesOff() { + sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off +} + +void Midi::resetDevices() { + MidiCleanup(); + MidiSetup(); +} + +void Midi::USBchanged() { + instance->MidiCleanup(); + instance->MidiSetup(); + instance->midiHardwareChange(); +} + +// + +QStringList Midi::listMidiDevices(bool output) { + QStringList rv; +#if defined Q_OS_WIN32 + if (output) { + MIDIOUTCAPS outcaps; + for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { + midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); + rv.append(outcaps.szPname); + } + } else { + MIDIINCAPS incaps; + for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { + midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); + rv.append(incaps.szPname); + } + } +#endif + return rv; +} + +void Midi::unblockMidiDevice(QString name, bool output) { + if (output) { + for (unsigned long i = 0; i < midiOutExclude.size(); i++) { + if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiOutExclude.erase(midiOutExclude.begin() + i); + break; + } + } + } else { + for (unsigned long i = 0; i < midiInExclude.size(); i++) { + if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { + midiInExclude.erase(midiInExclude.begin() + i); + break; + } + } + } +} + +void Midi::blockMidiDevice(QString name, bool output) { + unblockMidiDevice(name, output); // make sure it's only in there once + if (output) { + midiOutExclude.push_back(name); + } else { + midiInExclude.push_back(name); + } +} + +void Midi::thruModeEnable(bool enable) { + thruModeEnabled = enable; +} + +void Midi::broadcastEnable(bool enable) { + broadcastEnabled = enable; +} + +void Midi::typeNoteOffEnable(bool enable) { + typeNoteOffEnabled = enable; +} + +void Midi::typeNoteOnEnable(bool enable) { + typeNoteOnEnabled = enable; +} + +void Midi::typePolyKeyPressureEnable(bool enable) { + typePolyKeyPressureEnabled = enable; +} + +void Midi::typeControlChangeEnable(bool enable) { + typeControlChangeEnabled = enable; +} + +void Midi::typeProgramChangeEnable(bool enable) { + typeProgramChangeEnabled = enable; +} + +void Midi::typeChanPressureEnable(bool enable) { + typeChanPressureEnabled = enable; +} + +void Midi::typePitchBendEnable(bool enable) { + typePitchBendEnabled = enable; +} + +void Midi::typeSystemMessageEnable(bool enable) { + typeSystemMessageEnabled = enable; +} From fbfa5025474f6ee57031098fb13c28983157805c Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Fri, 19 Jan 2018 12:08:37 -0800 Subject: [PATCH 4/8] Delete Midi.h --- Midi.h | 108 --------------------------------------------------------- 1 file changed, 108 deletions(-) delete mode 100644 Midi.h diff --git a/Midi.h b/Midi.h deleted file mode 100644 index f7940bbe5d..0000000000 --- a/Midi.h +++ /dev/null @@ -1,108 +0,0 @@ -// -// Midi.h -// libraries/midi/src -// -// Created by Burt Sloane -// Modified by Bruce Brown -// Copyright 2015 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_Midi_h -#define hifi_Midi_h - -#include -#include -#include - -#include -#include - -class Midi : public QObject, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: - void midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program); // relay a note to Javascript - void midiHardwareChange(); // relay hardware change to Javascript - void sendRawMessage(int device, int raw); // relay midi message to MIDI outputs - void sendNote(int status, int note, int velocity); // relay a note to MIDI outputs - void sendMessage(int device, int channel, int type, int note, int velocity); // relay a message to MIDI outputs - static void USBchanged(); - -private: - static std::vector midiInExclude; - static std::vector midiOutExclude; - -private: - void MidiSetup(); - void MidiCleanup(); - -signals: - void midiNote(QVariantMap eventData); - void midiMessage(QVariantMap eventData); - void midiReset(); - - public slots: - // Send Raw Midi Packet to all connected devices - Q_INVOKABLE void sendRawDword(int device, int raw); - /// Send Raw Midi message to selected device - /// @param {int} device: device number - /// @param {int} raw: raw midi message (DWORD) - - // Send Midi Message to all connected devices - Q_INVOKABLE void sendMidiMessage(int device, int channel, int type, int note, int velocity); - /// Send midi message to selected device/devices - /// @param {int} device: device number - /// @param {int} channel: channel number - /// @param {int} type: 0x8 is noteoff, 0x9 is noteon (if velocity=0, noteoff), etc - /// @param {int} note: midi note number - /// @param {int} velocity: note velocity (0 means noteoff) - - // Send Midi Message to all connected devices - Q_INVOKABLE void playMidiNote(int status, int note, int velocity); - /// play a note on all connected devices - /// @param {int} status: 0x80 is noteoff, 0x90 is noteon (if velocity=0, noteoff), etc - /// @param {int} note: midi note number - /// @param {int} velocity: note velocity (0 means noteoff) - - /// turn off all notes on all connected devices - Q_INVOKABLE void allNotesOff(); - - /// clean up and re-discover attached devices - Q_INVOKABLE void resetDevices(); - - /// ask for a list of inputs/outputs - Q_INVOKABLE QStringList listMidiDevices(bool output); - - /// block an input/output by name - Q_INVOKABLE void blockMidiDevice(QString name, bool output); - - /// unblock an input/output by name - Q_INVOKABLE void unblockMidiDevice(QString name, bool output); - - /// repeat all incoming notes to all outputs (default disabled) - Q_INVOKABLE void thruModeEnable(bool enable); - - /// broadcast on all unblocked devices - Q_INVOKABLE void broadcastEnable(bool enable); - - /// filter by event types - Q_INVOKABLE void typeNoteOffEnable(bool enable); - Q_INVOKABLE void typeNoteOnEnable(bool enable); - Q_INVOKABLE void typePolyKeyPressureEnable(bool enable); - Q_INVOKABLE void typeControlChangeEnable(bool enable); - Q_INVOKABLE void typeProgramChangeEnable(bool enable); - Q_INVOKABLE void typeChanPressureEnable(bool enable); - Q_INVOKABLE void typePitchBendEnable(bool enable); - Q_INVOKABLE void typeSystemMessageEnable(bool enable); - - -public: - Midi(); - virtual ~Midi(); -}; - -#endif // hifi_Midi_h From e3fb9cee00c9dc3883bef05e19687499582e70b0 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Fri, 19 Jan 2018 12:09:07 -0800 Subject: [PATCH 5/8] Delete Midi.cpp --- Midi.cpp | 406 ------------------------------------------------------- 1 file changed, 406 deletions(-) delete mode 100644 Midi.cpp diff --git a/Midi.cpp b/Midi.cpp deleted file mode 100644 index ec13508805..0000000000 --- a/Midi.cpp +++ /dev/null @@ -1,406 +0,0 @@ -// -// Midi.cpp -// libraries/midi/src -// -// Created by Burt Sloane -// Modified by Bruce Brown -// Copyright 2015 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 "Midi.h" - - -#include - -#if defined Q_OS_WIN32 -#include "Windows.h" -#endif - -#if defined Q_OS_WIN32 -const int MIDI_BYTE_MASK = 0x0FF; -const int MIDI_NIBBLE_MASK = 0x00F; -const int MIDI_PITCH_BEND_MASK = 0x3F80; -const int MIDI_SHIFT_STATUS = 4; -const int MIDI_SHIFT_NOTE = 8; -const int MIDI_SHIFT_VELOCITY = 16; -const int MIDI_SHIFT_PITCH_BEND = 9; -// Status Decode -const int MIDI_NOTE_OFF = 0x8; -const int MIDI_NOTE_ON = 0x9; -const int MIDI_POLYPHONIC_KEY_PRESSURE = 0xa; -const int MIDI_PROGRAM_CHANGE = 0xc; -const int MIDI_CHANNEL_PRESSURE = 0xd; -const int MIDI_PITCH_BEND_CHANGE = 0xe; -const int MIDI_SYSTEM_MESSAGE = 0xf; -#endif - -const int MIDI_CONTROL_CHANGE = 0xb; -const int MIDI_CHANNEL_MODE_ALL_NOTES_OFF = 0x07b; - -static Midi* instance = NULL; // communicate this to non-class callbacks -static bool thruModeEnabled = false; -static bool broadcastEnabled = false; -static bool typeNoteOffEnabled = true; -static bool typeNoteOnEnabled = true; -static bool typePolyKeyPressureEnabled = false; -static bool typeControlChangeEnabled = true; -static bool typeProgramChangeEnabled = true; -static bool typeChanPressureEnabled = false; -static bool typePitchBendEnabled = true; -static bool typeSystemMessageEnabled = false; - -std::vector Midi::midiInExclude; -std::vector Midi::midiOutExclude; - -#if defined Q_OS_WIN32 - -#pragma comment(lib, "Winmm.lib") - -// -std::vector midihin; -std::vector midihout; - -void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MIM_OPEN: - // message not used - break; - case MIM_CLOSE: - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - midihin[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - case MIM_DATA: { - int device = -1; - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] == hMidiIn) { - device = i; - } - } - int raw = dwParam1; - int channel = (MIDI_NIBBLE_MASK & dwParam1) + 1; - int status = MIDI_BYTE_MASK & dwParam1; - int type = MIDI_NIBBLE_MASK & (dwParam1 >> MIDI_SHIFT_STATUS); - int note = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE); - int velocity = MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_VELOCITY); - int bend = 0; - int program = 0; - if (!typeNoteOffEnabled && type == MIDI_NOTE_OFF) { - return; - } - if (!typeNoteOnEnabled && type == MIDI_NOTE_ON) { - return; - } - if (!typePolyKeyPressureEnabled && type == MIDI_POLYPHONIC_KEY_PRESSURE) { - return; - } - if (!typeControlChangeEnabled && type == MIDI_CONTROL_CHANGE) { - return; - } - if (typeProgramChangeEnabled && type == MIDI_PROGRAM_CHANGE) { - program = note; - note = 0; - } - if (typeChanPressureEnabled && type == MIDI_CHANNEL_PRESSURE) { - velocity = note; - note = 0; - } - if (typePitchBendEnabled && type == MIDI_PITCH_BEND_CHANGE) { - bend = ((MIDI_BYTE_MASK & (dwParam1 >> MIDI_SHIFT_NOTE)) | - (MIDI_PITCH_BEND_MASK & (dwParam1 >> MIDI_SHIFT_PITCH_BEND))) - 8192; - channel = 0; // Weird values on different instruments - note = 0; - velocity = 0; - } - if (!typeSystemMessageEnabled && type == MIDI_SYSTEM_MESSAGE) { - return; - } - if (thruModeEnabled) { - instance->sendNote(status, note, velocity); // relay the message on to all other midi devices. - } - instance->midiReceived(device, raw, channel, status, type, note, velocity, bend, program); // notify the javascript - break; - } - } -} - -void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - switch (wMsg) { - case MOM_OPEN: - // message not used - break; - case MOM_CLOSE: - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] == hmo) { - midihout[i] = NULL; - instance->allNotesOff(); - instance->midiHardwareChange(); - } - } - break; - } -} - -void Midi::sendRawMessage(int device, int raw) { - if (broadcastEnabled) { - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], raw); - } - } - } else { - midiOutShortMsg(midihout[device], raw); - } -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity) { - int message = (channel - 1) | (type << MIDI_SHIFT_STATUS); - if (broadcastEnabled) { - for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } - } - } else { - midiOutShortMsg(midihout[device], message | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); - } -} - -void Midi::sendNote(int status, int note, int velocity) { - for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) - if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); - } - } -} - -void Midi::MidiSetup() { - midihin.clear(); - midihout.clear(); - - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiInExclude.size(); j++) { - if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN INPUT BY NAME - HMIDIIN tmphin; - midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); - midiInStart(tmphin); - midihin.push_back(tmphin); - } - } - - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - - bool found = false; - for (int j = 0; j < midiOutExclude.size(); j++) { - if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { - found = true; - break; - } - } - if (!found) { // EXCLUDE AN OUTPUT BY NAME - HMIDIOUT tmphout; - midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION); - midihout.push_back(tmphout); - } - } - - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); - - for (int i = 0; i < midihin.size(); i++) { - if (midihin[i] != NULL) { - midiInStop(midihin[i]); - midiInClose(midihin[i]); - } - } - for (int i = 0; i < midihout.size(); i++) { - if (midihout[i] != NULL) { - midiOutClose(midihout[i]); - } - } - midihin.clear(); - midihout.clear(); -} -#else -void Midi::sendRawMessage(int device, int raw) { -} - -void Midi::sendNote(int status, int note, int velocity) { -} - -void Midi::sendMessage(int device, int channel, int type, int note, int velocity){ -} - -void Midi::MidiSetup() { - allNotesOff(); -} - -void Midi::MidiCleanup() { - allNotesOff(); -} -#endif - -void Midi::midiReceived(int device, int raw, int channel, int status, int type, int note, int velocity, int bend, int program) { - QVariantMap eventData; - eventData["device"] = device; - eventData["raw"] = raw; - eventData["channel"] = channel; - eventData["status"] = status; - eventData["type"] = type; - eventData["note"] = note; - eventData["velocity"] = velocity; - eventData["bend"] = bend; - eventData["program"] = program; - emit midiNote(eventData);// Legacy - emit midiMessage(eventData); -} - -void Midi::midiHardwareChange() { - emit midiReset(); -} -// - -Midi::Midi() { - instance = this; - MidiSetup(); -} - -Midi::~Midi() { -} - -void Midi::sendRawDword(int device, int raw) { - sendRawMessage(device, raw); -} - -void Midi::playMidiNote(int status, int note, int velocity) { - sendNote(status, note, velocity); -} - -void Midi::sendMidiMessage(int device, int channel, int type, int note, int velocity) { - sendMessage(device, channel, type, note, velocity); -} - -void Midi::allNotesOff() { - sendNote(MIDI_CONTROL_CHANGE, MIDI_CHANNEL_MODE_ALL_NOTES_OFF, 0); // all notes off -} - -void Midi::resetDevices() { - MidiCleanup(); - MidiSetup(); -} - -void Midi::USBchanged() { - instance->MidiCleanup(); - instance->MidiSetup(); - instance->midiHardwareChange(); -} - -// - -QStringList Midi::listMidiDevices(bool output) { - QStringList rv; -#if defined Q_OS_WIN32 - if (output) { - MIDIOUTCAPS outcaps; - for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { - midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - rv.append(outcaps.szPname); - } - } else { - MIDIINCAPS incaps; - for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { - midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - rv.append(incaps.szPname); - } - } -#endif - return rv; -} - -void Midi::unblockMidiDevice(QString name, bool output) { - if (output) { - for (unsigned long i = 0; i < midiOutExclude.size(); i++) { - if (midiOutExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiOutExclude.erase(midiOutExclude.begin() + i); - break; - } - } - } else { - for (unsigned long i = 0; i < midiInExclude.size(); i++) { - if (midiInExclude[i].toStdString().compare(name.toStdString()) == 0) { - midiInExclude.erase(midiInExclude.begin() + i); - break; - } - } - } -} - -void Midi::blockMidiDevice(QString name, bool output) { - unblockMidiDevice(name, output); // make sure it's only in there once - if (output) { - midiOutExclude.push_back(name); - } else { - midiInExclude.push_back(name); - } -} - -void Midi::thruModeEnable(bool enable) { - thruModeEnabled = enable; -} - -void Midi::broadcastEnable(bool enable) { - broadcastEnabled = enable; -} - -void Midi::typeNoteOffEnable(bool enable) { - typeNoteOffEnabled = enable; -} - -void Midi::typeNoteOnEnable(bool enable) { - typeNoteOnEnabled = enable; -} - -void Midi::typePolyKeyPressureEnable(bool enable) { - typePolyKeyPressureEnabled = enable; -} - -void Midi::typeControlChangeEnable(bool enable) { - typeControlChangeEnabled = enable; -} - -void Midi::typeProgramChangeEnable(bool enable) { - typeProgramChangeEnabled = enable; -} - -void Midi::typeChanPressureEnable(bool enable) { - typeChanPressureEnabled = enable; -} - -void Midi::typePitchBendEnable(bool enable) { - typePitchBendEnabled = enable; -} - -void Midi::typeSystemMessageEnable(bool enable) { - typeSystemMessageEnabled = enable; -} From fab13a111c8a15213597712aabe110463b8bbca4 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Fri, 19 Jan 2018 13:10:34 -0800 Subject: [PATCH 6/8] Remove accidental - --- libraries/midi/src/Midi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 7f086340ba..1f1d581e48 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -24,7 +24,7 @@ const int MIDI_BYTE_MASK = 0x0FF; const int MIDI_NIBBLE_MASK = 0x00F; const int MIDI_PITCH_BEND_MASK = 0x3F80; const int MIDI_SHIFT_STATUS = 4; -const int MIDI_SHIFT_NOTE = 8;- +const int MIDI_SHIFT_NOTE = 8; const int MIDI_SHIFT_VELOCITY = 16; const int MIDI_SHIFT_PITCH_BEND = 9; // Status Decode From cbc8698e9a3273f12c7ccdbc79b089eb2bbecd15 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Fri, 19 Jan 2018 16:59:47 -0800 Subject: [PATCH 7/8] Fix Bitwise operators. --- libraries/midi/src/Midi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 1f1d581e48..1f190111f2 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -176,7 +176,7 @@ void Midi::sendMessage(int device, int channel, int type, int note, int velocity void Midi::sendNote(int status, int note, int velocity) { for (int i = 1; i < midihout.size(); i++) { // Skip 0 (Microsoft GS Wavetable Synth) if (midihout[i] != NULL) { - midiOutShortMsg(midihout[i], status + (note << MIDI_SHIFT_NOTE) + (velocity << MIDI_SHIFT_VELOCITY)); + midiOutShortMsg(midihout[i], status | (note << MIDI_SHIFT_NOTE) | (velocity << MIDI_SHIFT_VELOCITY)); } } } From f7caba5295680e713c45849a7b97654ac3123281 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Sat, 20 Jan 2018 11:17:47 -0800 Subject: [PATCH 8/8] de-bounce Midi::USBchanged signal. Debounced USBchanged signal to prevent pauses. --- interface/src/Application.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4b96bc2f2e..3cfa5338ba 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -503,7 +503,13 @@ public: } if (message->message == WM_DEVICECHANGE) { - Midi::USBchanged(); // re-scan the MIDI bus + const float MIN_DELTA_SECONDS = 2.0f; // de-bounce signal + static float lastTriggerTime = 0.0f; + const float deltaSeconds = secTimestampNow() - lastTriggerTime; + lastTriggerTime = secTimestampNow(); + if (deltaSeconds > MIN_DELTA_SECONDS) { + Midi::USBchanged(); // re-scan the MIDI bus + } } } return false;