Reading multiple midi input

#1

Hi, I am a new user of OF. I want to receive and process multiple midi port at the same time, but I do not know how. I use ofxMidi now.

#2

Hi, I think that if you just follow ofxMidi examples, you could just create more than a single instance of ofxMidiInput and ofxMidiOutput, and set these to open the different ports you want to use.

#3

I created instance, but all ports closed at the moment of execution.
main.cpp

#include "ofMain.h"
#include "ofApp.h"

int main() {
	ofSetupOpenGL(640, 480, OF_WINDOW);
	ofRunApp(new ofApp());
}

ofApp.cpp

/*
 * Copyright (c) 2013 Dan Wilcox <danomatika@gmail.com>
 *
 * BSD Simplified License.
 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
 * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
 *
 * See https://github.com/danomatika/ofxMidi for documentation
 *
 */
#include "ofApp.h"

 //--------------------------------------------------------------

void ofApp::setup() {
	ofApp first, second;
		ofSetVerticalSync(true);
		ofBackground(255, 255, 255);
		ofSetLogLevel(OF_LOG_VERBOSE);

		// print input ports to console
		midiIn.listInPorts();

		// open port by number (you may need to change this)
		first.midiIn.openPort(1);
		second.midiIn.openPort(2);

		// don't ignore sysex, timing, & active sense messages,		
		//midiIn.openPort("IAC Pure Data In");	// by name
		//midiIn.openVirtualPort("ofxMidiIn Input"); // open a virtual port
		// these are ignored by default
		first.midiIn.ignoreTypes(false, false, false);
		second.midiIn.ignoreTypes(false, false, false);

		// add ofApp as a listener
		midiIn.addListener(this);

		// print received messages to the console
		first.midiIn.setVerbose(true);

		// print received messages to the console
		second.midiIn.setVerbose(true);
	
}

//--------------------------------------------------------------
void ofApp::update() {
	
}

//--------------------------------------------------------------
void ofApp::draw() {


	for (unsigned int i = 0; i < midiMessages.size(); ++i) {

		ofxMidiMessage& message = midiMessages[i];
		int x = 10;
		int y = i * 40 + 40;

		// draw the last recieved message contents to the screen,
		// this doesn't print all the data from every status type
		// but you should get the general idea
		stringstream text;
		text << ofxMidiMessage::getStatusString(message.status);
		while (text.str().length() < 16) { // pad status width
			text << " ";
		}

		ofSetColor(127);
		if (message.status < MIDI_SYSEX) {
			text << "chan: " << message.channel;
			if (message.status == MIDI_CONTROL_CHANGE) {
				text << "\tctl: " << message.control;
				ofDrawRectangle(x + ofGetWidth() * 0.2, y + 12,
					ofMap(message.control, 0, 127, 0, ofGetWidth() * 0.2), 10);
			}
			else if (message.status == MIDI_PITCH_BEND) {
				text << "\tval: " << message.value;
				ofDrawRectangle(x + ofGetWidth() * 0.2, y + 12,
					ofMap(message.value, 0, MIDI_MAX_BEND, 0, ofGetWidth() * 0.2), 10);
			}
			else {
				text << "\tpitch: " << message.pitch;
				ofDrawRectangle(x + ofGetWidth() * 0.2, y + 12,
					ofMap(message.pitch, 0, 127, 0, ofGetWidth() * 0.2), 10);

				text << "\tvel: " << message.velocity;
				ofDrawRectangle(x + (ofGetWidth() * 0.2 * 2), y + 12,
					ofMap(message.velocity, 0, 127, 0, ofGetWidth() * 0.2), 10);
			}
			text << " "; // pad for delta print
		}

		text << "delta: " << message.deltatime;
		ofSetColor(0);
		ofDrawBitmapString(text.str(), x, y);
		text.str(""); // clear
	}
}

//--------------------------------------------------------------
void ofApp::exit() {

	// clean up
	midiIn.closePort();
	midiIn.removeListener(this);
}

//--------------------------------------------------------------
void ofApp::newMidiMessage(ofxMidiMessage& msg) {

	// add the latest message to the message queue
	midiMessages.push_back(msg);

	// remove any old messages if we have too many
	while (midiMessages.size() > maxMessages) {
		midiMessages.erase(midiMessages.begin());
	}
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key) {
	switch (key) {
	case '?':
		midiIn.listInPorts();
		break;
	}
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key) {
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y) {
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button) {
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {
}

//--------------------------------------------------------------
void ofApp::mouseReleased() {
}

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxMidi.h"

class ofApp : public ofBaseApp, public ofxMidiListener {

public:
	
	void setup();
	void update();
	void draw();
	
	void exit();
	
	void keyPressed(int key);
	void keyReleased(int key);

	void mouseMoved(int x, int y);
	void mouseDragged(int x, int y, int button);
	void mousePressed(int x, int y, int button);
	void mouseReleased();

	void newMidiMessage(ofxMidiMessage& eventArgs);

	ofxMidiIn midiIn;
	std::vector<ofxMidiMessage> midiMessages;
	std::size_t maxMessages = 10; //< max number of messages to keep track of
	
};

Console
[notice ] ofxMidiIn: 3 ports available
[notice ] ofxMidiIn: 0: 2- A-Series Keyboard 0
[notice ] ofxMidiIn: 1: midi1 1
[notice ] ofxMidiIn: 2: midi2 2
[verbose] ofxMidiIn: opened port 1 midi1 1
[verbose] ofxMidiIn: opened port 2 midi2 2
[verbose] ofxMidiIn: ignore types on midi1 1: sysex: 0 timing: 0 sense: 0
[verbose] ofxMidiIn: ignore types on midi2 2: sysex: 0 timing: 0 sense: 0
[verbose] ofxMidiIn: closing port 2 midi2 2
[verbose] ofxMidiIn: closing port 1 midi1 1

#4

Hi!
You’ve got to create two ofxMidiIn objects, not two ofApp’s.
(Not even sure what happens when you do that, guess their update() and draw() functions aren’t getting called, because they’re made outside the ofRunApp() in main.h?)
Anyway.
In the midiInputExample in ofxMidi declare the two inputs in ofApp.h

	ofxMidiIn midiIn; // Or give them a better name: "fromSuperCollider", "akaiInput"
    ofxMidiIn midiIn2;

In ofApp.cpp you can do the same for each input:

	midiIn.openPort(0);
    midiIn2.openPort(1);

	midiIn.ignoreTypes(false, false, false);
    midiIn2.ignoreTypes(false, false, false);
	
	midiIn.addListener(this);
    midiIn2.addListener(this);
	
	midiIn.setVerbose(true);
    midiIn2.setVerbose(true);

Tested it with internal MIDI from SuperCollider, and it works here :slight_smile: Good luck!

#5

Thank you very much!
I use windows and vs2017 now.
I confirmed that I can receive and process a loopmidi signal and an usbmidi device signal simultaneously, but I get a debug assertion failed when receiving multiple signals from loopmidi.
I do not know how to fix it…
I attached console images

#6

Hi
Maybe you’ve got to use two ofxMidiMessage objects to store the data?
Sounds a bit like this:


Good luck

#7

Thank you very much!
I used two ofxMidiMessage objects and stored data in each objects.
It worked normally!

ofApp.cpp

void ofApp::newMidiMessage(ofxMidiMessage& msg) {

	if (msg.portNum == 1) {
		midiMessages.push_back(msg);
		while (midiMessages.size() > maxMessages) {
			midiMessages.erase(midiMessages.begin());
		}
	}
	else {
		midiMessages2.push_back(msg);
		while (midiMessages2.size() > maxMessages) {
			midiMessages2.erase(midiMessages2.begin());
		}
	}
	
}

ofApp.h

std::vector<ofxMidiMessage> midiMessages;
std::vector<ofxMidiMessage> midiMessages2;
1 Like