Okay, here’s my juce_linux_midi.cpp, using ALSA’s sequencer API, so you can do inter-app connections :D. It’s not by any means complete - it only handles MIDI input, and I left out anything I don’t actually need (timestamps, sysex etc.), but it works well:
[code]/*
This file is part of the JUCE library - "Jules’ Utility Class Extensions"
Copyright 2004-6 by Raw Material Software ltd.
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
If you’d like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
#include “juce_Config.h”
#if JUCE_BUILD_GUI_CLASSES
#include “…/…/…/src/juce_core/basics/juce_StandardHeader.h”
#include “alsa/asoundlib.h”
#include
using namespace std;
BEGIN_JUCE_NAMESPACE
#include “…/…/…/src/juce_appframework/audio/devices/juce_MidiOutput.h”
#include “…/…/…/src/juce_appframework/audio/devices/juce_MidiInput.h”
#include “…/…/…/src/juce_core/threads/juce_Thread.h”
//==============================================================================
const StringArray MidiOutput::getDevices()
{
StringArray s;
return s;
}
int MidiOutput::getDefaultDeviceIndex()
{
return 0;
}
MidiOutput* MidiOutput::openDevice (int deviceIndex)
{
return 0;
}
MidiOutput::MidiOutput()
{
}
MidiOutput::~MidiOutput()
{
}
void MidiOutput::reset()
{
}
bool MidiOutput::getVolume (float& leftVol, float& rightVol)
{
return false;
}
void MidiOutput::setVolume (float leftVol, float rightVol)
{
}
void MidiOutput::sendMessageNow (const MidiMessage& message)
{
}
//==============================================================================
//------------------------------------------------------------------------------
/// Thread used to handle all MIDI input.
class MidiInputThread : public Thread
{
public:
/// Constructor.
/*!
\param input Pointer to the MidiInput object in charge of the MIDI
stuff.
\param handle Handle to the sequencer object used to receive MIDI events
from.
\param inputCallback Pointer to the callback object to be called when
a MIDI event is received.
*/
MidiInputThread(MidiInput *input,
snd_seq_t *handle,
MidiInputCallback * const inputCallback):
Thread(T(“JUCE MIDI Input Thread”)),
midiInput(input),
seqHandle(handle),
callback(inputCallback)
{
};
/// Destructor.
~MidiInputThread()
{
if(seqHandle)
{
//Do I need to do anything else?
snd_seq_close(seqHandle);
}
};
/// Where the main thread activity takes place.
void run()
{
int npfd = -1;
struct pollfd *pfd = 0;
snd_seq_event_t *event = 0;
unsigned char tempBytes[32];
snd_midi_event_t *midiParser;
int byteCount;
if(snd_midi_event_new(32, &midiParser) != 0)
{
cout << "Could not create MIDI parser." << endl;
midiParser = 0;
}
//Polling code taken from:
//http://www.suse.de/~mana/seqdemo.c
if(seqHandle)
{
npfd = snd_seq_poll_descriptors_count(seqHandle, POLLIN);
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
snd_seq_poll_descriptors(seqHandle, pfd, npfd, POLLIN);
while(!threadShouldExit())
{
if(poll(pfd, npfd, 200) > 0)
{
while(snd_seq_event_input(seqHandle, &event) >= 0)
{
if(!midiParser)
continue;
byteCount = snd_midi_event_decode(midiParser,
tempBytes,
32,
event);
snd_midi_event_reset_decode(midiParser);
//Ignore timestamp for now (not sure what to do with
//it?).
const MidiMessage message((const uint8 * const)tempBytes,
byteCount);
callback->handleIncomingMidiMessage(midiInput, message);
}
//Should this be inside the above loop?
snd_seq_free_event(event);
}
}
}
if(midiParser)
snd_midi_event_free(midiParser);
};
juce_UseDebuggingNewOperator
private:
/// The MidiInput object associated with this thread.
MidiInput *midiInput;
/// The sequencer handle for this client.
snd_seq_t *seqHandle;
/// The callback to call when we receive a MIDI event.
MidiInputCallback *callback;
};
const StringArray MidiInput::getDevices()
{
StringArray s;
snd_seq_t *seqHandle;
snd_seq_system_info_t *info;
snd_seq_client_info_t *info2;
snd_seq_port_info_t *portInfo;
if(snd_seq_open(&seqHandle, "default", SND_SEQ_OPEN_INPUT, 0) < 0)
{
cout << "Could not open ALSA seq client." << endl;
return s;
}
if(!snd_seq_system_info_malloc(&info))
{
if(!snd_seq_system_info(seqHandle, info))
{
if(!snd_seq_client_info_malloc(&info2))
{
int tempint = snd_seq_system_info_get_cur_clients(info);
for(int i=0;i<tempint;++i)
{
if(!snd_seq_query_next_client(seqHandle, info2))
{
if(!snd_seq_port_info_malloc(&portInfo))
{
int tempint2;
int tempint3 = snd_seq_client_info_get_num_ports(info2);
tempint2 = snd_seq_client_info_get_client(info2);
snd_seq_port_info_set_client(portInfo, tempint2);
snd_seq_port_info_set_port(portInfo, -1);
for(int j=0;j<tempint3;++j)
{
if(!snd_seq_query_next_port(seqHandle, portInfo))
{
unsigned int caps;
caps = snd_seq_port_info_get_capability(portInfo);
if(caps&SND_SEQ_PORT_CAP_READ)
{
s.add(snd_seq_client_info_get_name(info2));
}
}
}
snd_seq_port_info_free(portInfo);
}
}
else
cout << "Could not get client info " << i << endl;
}
if(!snd_seq_get_client_info(seqHandle, info2))
{
cout << "Got current client info." << endl;
cout << "Client ID: ";
cout << snd_seq_client_info_get_client(info2) << endl;
cout << "Client name: ";
cout << snd_seq_client_info_get_name(info2) << endl;
}
snd_seq_client_info_free(info2);
}
}
else
cout << "Could not get ALSA seq system info." << endl;
snd_seq_system_info_free(info);
}
else
cout << "Could not allocate system info struct." << endl;
snd_seq_close(seqHandle);
return s;
}
int MidiInput::getDefaultDeviceIndex()
{
return 0;
}
MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback)
{
snd_seq_t *seqHandle;
snd_seq_system_info_t *info;
snd_seq_client_info_t *info2;
snd_seq_port_info_t *portInfo;
int portId;
int sourcePort = -1;
int currentIndex = -1;
MidiInput *retval = 0;
MidiInputThread *thread;
if(snd_seq_open(&seqHandle, "default", SND_SEQ_OPEN_INPUT, 0) < 0)
return 0;
if(!snd_seq_system_info_malloc(&info))
{
if(!snd_seq_system_info(seqHandle, info))
{
if(!snd_seq_client_info_malloc(&info2))
{
int tempint = snd_seq_system_info_get_cur_clients(info);
for(int i=0;i<tempint;++i)
{
if(!snd_seq_query_next_client(seqHandle, info2))
{
if(!snd_seq_port_info_malloc(&portInfo))
{
int tempint2;
int tempint3 = snd_seq_client_info_get_num_ports(info2);
tempint2 = snd_seq_client_info_get_client(info2);
snd_seq_port_info_set_client(portInfo, tempint2);
snd_seq_port_info_set_port(portInfo, -1);
for(int j=0;j<tempint3;++j)
{
if(!snd_seq_query_next_port(seqHandle, portInfo))
{
unsigned int caps;
sourcePort = snd_seq_port_info_get_port(portInfo);
caps = snd_seq_port_info_get_capability(portInfo);
if(caps&SND_SEQ_PORT_CAP_READ)
{
++currentIndex;
break;
}
}
}
if((currentIndex == deviceIndex) &&
(sourcePort != -1))
{
String tempstr;
int sourceClient;
//Get client name, put into tempstr.
tempstr << snd_seq_client_info_get_name(info2);
//Set name for our client.
snd_seq_set_client_name(seqHandle,
"JUCE Midi Input");
//Open port for seqHandle (do I need to save the ID?).
portId = snd_seq_create_simple_port(seqHandle,
"JUCE Midi In Port",
SND_SEQ_PORT_CAP_WRITE,
SND_SEQ_PORT_TYPE_MIDI_GENERIC);
//Subscribe to relevant client port.
sourceClient = snd_seq_client_info_get_client(info2);
snd_seq_connect_from(seqHandle,
portId,
sourceClient,
sourcePort);
retval = new MidiInput(tempstr);
thread = new MidiInputThread(retval,
seqHandle,
callback);
retval->internal = thread;
snd_seq_port_info_free(portInfo);
break;
}
snd_seq_port_info_free(portInfo);
}
}
}
snd_seq_client_info_free(info2);
}
}
snd_seq_system_info_free(info);
}
if(!retval)
snd_seq_close(seqHandle);
return retval;
}
MidiInput::~MidiInput()
{
MidiInputThread *thread;
if(internal)
{
thread = (MidiInputThread *)internal;
delete thread;
}
}
MidiInput::MidiInput(const String &name_):
internal(0),
name(name_)
{
}
void MidiInput::start()
{
((MidiInputThread *)internal)->startThread();
}
void MidiInput::stop()
{
((MidiInputThread *)internal)->stopThread(250);
}
END_JUCE_NAMESPACE
#endif
[/code]