|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 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
-
- #if JUCE_ALSA
-
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
- #include <alsa/asoundlib.h>
-
- 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"
- #include "../../../src/juce_core/basics/juce_Time.h"
-
-
- //==============================================================================
- static snd_seq_t* iterateDevices (const bool forInput,
- StringArray& deviceNamesFound,
- const int deviceIndexToOpen)
- {
- snd_seq_t* returnedHandle = 0;
- snd_seq_t* seqHandle;
-
- if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
- : SND_SEQ_OPEN_OUTPUT, 0) == 0)
- {
- snd_seq_system_info_t* systemInfo;
- snd_seq_client_info_t* clientInfo;
-
- if (snd_seq_system_info_malloc (&systemInfo) == 0)
- {
- if (snd_seq_system_info (seqHandle, systemInfo) == 0
- && snd_seq_client_info_malloc (&clientInfo) == 0)
- {
- int numClients = snd_seq_system_info_get_cur_clients (systemInfo);
-
- while (--numClients >= 0 && returnedHandle == 0)
- {
- if (snd_seq_query_next_client (seqHandle, clientInfo) == 0)
- {
- snd_seq_port_info_t* portInfo;
- if (snd_seq_port_info_malloc (&portInfo) == 0)
- {
- int numPorts = snd_seq_client_info_get_num_ports (clientInfo);
- const int client = snd_seq_client_info_get_client (clientInfo);
-
- snd_seq_port_info_set_client (portInfo, client);
- snd_seq_port_info_set_port (portInfo, -1);
-
- while (--numPorts >= 0)
- {
- if (snd_seq_query_next_port (seqHandle, portInfo) == 0
- && (snd_seq_port_info_get_capability (portInfo)
- & (forInput ? SND_SEQ_PORT_CAP_READ
- : SND_SEQ_PORT_CAP_WRITE)) != 0)
- {
- deviceNamesFound.add (snd_seq_client_info_get_name (clientInfo));
-
- if (deviceNamesFound.size() == deviceIndexToOpen + 1)
- {
- const int sourcePort = snd_seq_port_info_get_port (portInfo);
- const int sourceClient = snd_seq_client_info_get_client (clientInfo);
-
- if (sourcePort != -1)
- {
- snd_seq_set_client_name (seqHandle,
- forInput ? "Juce Midi Input"
- : "Juce Midi Output");
-
- const int portId
- = snd_seq_create_simple_port (seqHandle,
- forInput ? "Juce Midi In Port"
- : "Juce Midi Out Port",
- forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
- : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
- SND_SEQ_PORT_TYPE_MIDI_GENERIC);
-
- snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort);
-
- returnedHandle = seqHandle;
- break;
- }
- }
- }
- }
-
- snd_seq_port_info_free (portInfo);
- }
- }
- }
-
- snd_seq_client_info_free (clientInfo);
- }
-
- snd_seq_system_info_free (systemInfo);
- }
-
- if (returnedHandle == 0)
- snd_seq_close (seqHandle);
- }
-
- deviceNamesFound.appendNumbersToDuplicates (true, true);
-
- return returnedHandle;
- }
-
- static snd_seq_t* createDevice (const bool forInput,
- const String& deviceNameToOpen)
- {
- snd_seq_t* seqHandle = 0;
-
- if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
- : SND_SEQ_OPEN_OUTPUT, 0) == 0)
- {
- snd_seq_set_client_name (seqHandle,
- (const char*) (forInput ? (deviceNameToOpen + T(" Input"))
- : (deviceNameToOpen + T(" Output"))));
-
- const int portId
- = snd_seq_create_simple_port (seqHandle,
- forInput ? "in"
- : "out",
- forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
- : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
- forInput ? SND_SEQ_PORT_TYPE_APPLICATION
- : SND_SEQ_PORT_TYPE_MIDI_GENERIC);
-
- if (portId < 0)
- {
- snd_seq_close (seqHandle);
- seqHandle = 0;
- }
- }
-
- return seqHandle;
- }
-
- //==============================================================================
- class MidiOutputDevice
- {
- public:
- MidiOutputDevice (MidiOutput* const midiOutput_,
- snd_seq_t* const seqHandle_)
- :
- midiOutput (midiOutput_),
- seqHandle (seqHandle_),
- maxEventSize (16 * 1024)
- {
- jassert (seqHandle != 0 && midiOutput != 0);
- snd_midi_event_new (maxEventSize, &midiParser);
- }
-
- ~MidiOutputDevice()
- {
- snd_midi_event_free (midiParser);
- snd_seq_close (seqHandle);
- }
-
- void sendMessageNow (const MidiMessage& message)
- {
- if (message.getRawDataSize() > maxEventSize)
- {
- maxEventSize = message.getRawDataSize();
- snd_midi_event_free (midiParser);
- snd_midi_event_new (maxEventSize, &midiParser);
- }
-
- snd_seq_event_t event;
- snd_seq_ev_clear (&event);
-
- snd_midi_event_encode (midiParser,
- message.getRawData(),
- message.getRawDataSize(),
- &event);
-
- snd_midi_event_reset_encode (midiParser);
-
- snd_seq_ev_set_source (&event, 0);
- snd_seq_ev_set_subs (&event);
- snd_seq_ev_set_direct (&event);
-
- snd_seq_event_output_direct (seqHandle, &event);
- }
-
- juce_UseDebuggingNewOperator
-
- private:
- MidiOutput* const midiOutput;
- snd_seq_t* const seqHandle;
- snd_midi_event_t* midiParser;
- int maxEventSize;
- };
-
- const StringArray MidiOutput::getDevices()
- {
- StringArray devices;
- iterateDevices (false, devices, -1);
- return devices;
- }
-
- int MidiOutput::getDefaultDeviceIndex()
- {
- return 0;
- }
-
- MidiOutput* MidiOutput::openDevice (int deviceIndex)
- {
- MidiOutput* newDevice = 0;
-
- StringArray devices;
- snd_seq_t* const handle = iterateDevices (false, devices, deviceIndex);
-
- if (handle != 0)
- {
- newDevice = new MidiOutput();
- newDevice->internal = new MidiOutputDevice (newDevice, handle);
- }
-
- return newDevice;
- }
-
- MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
- {
- MidiOutput* newDevice = 0;
-
- snd_seq_t* const handle = createDevice (false, deviceName);
-
- if (handle != 0)
- {
- newDevice = new MidiOutput();
- newDevice->internal = new MidiOutputDevice (newDevice, handle);
- }
-
- return newDevice;
- }
-
- MidiOutput::~MidiOutput()
- {
- MidiOutputDevice* const device = (MidiOutputDevice*) internal;
- delete device;
- }
-
- 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)
- {
- ((MidiOutputDevice*) internal)->sendMessageNow (message);
- }
-
-
- //==============================================================================
- class MidiInputThread : public Thread
- {
- public:
- MidiInputThread (MidiInput* const midiInput_,
- snd_seq_t* const seqHandle_,
- MidiInputCallback* const callback_)
- : Thread (T("Juce MIDI Input")),
- midiInput (midiInput_),
- seqHandle (seqHandle_),
- callback (callback_)
- {
- jassert (seqHandle != 0 && callback != 0 && midiInput != 0);
- }
-
- ~MidiInputThread()
- {
- snd_seq_close (seqHandle);
- }
-
- void run()
- {
- const int maxEventSize = 16 * 1024;
- snd_midi_event_t* midiParser;
-
- if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
- {
- uint8* const buffer = (uint8*) juce_malloc (maxEventSize);
-
- const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
- struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd));
-
- snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN);
-
- while (! threadShouldExit())
- {
- if (poll (pfd, numPfds, 500) > 0)
- {
- snd_seq_event_t* inputEvent = 0;
-
- snd_seq_nonblock (seqHandle, 1);
-
- do
- {
- if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
- {
- // xxx what about SYSEXes that are too big for the buffer?
- const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent);
-
- snd_midi_event_reset_decode (midiParser);
-
- if (numBytes > 0)
- {
- const MidiMessage message ((const uint8*) buffer,
- numBytes,
- Time::getMillisecondCounter() * 0.001);
-
-
- callback->handleIncomingMidiMessage (midiInput, message);
- }
-
- snd_seq_free_event (inputEvent);
- }
- }
- while (snd_seq_event_input_pending (seqHandle, 0) > 0);
-
- snd_seq_free_event (inputEvent);
- }
- }
-
- snd_midi_event_free (midiParser);
- juce_free (buffer);
- }
- };
-
- juce_UseDebuggingNewOperator
-
- private:
- MidiInput* const midiInput;
- snd_seq_t* const seqHandle;
- MidiInputCallback* const callback;
- };
-
- //==============================================================================
- MidiInput::MidiInput (const String& name_)
- : name (name_),
- internal (0)
- {
- }
-
- MidiInput::~MidiInput()
- {
- stop();
- MidiInputThread* const thread = (MidiInputThread*) internal;
- delete thread;
- }
-
- void MidiInput::start()
- {
- ((MidiInputThread*) internal)->startThread();
- }
-
- void MidiInput::stop()
- {
- ((MidiInputThread*) internal)->stopThread (3000);
- }
-
- int MidiInput::getDefaultDeviceIndex()
- {
- return 0;
- }
-
- const StringArray MidiInput::getDevices()
- {
- StringArray devices;
- iterateDevices (true, devices, -1);
- return devices;
- }
-
- MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback)
- {
- MidiInput* newDevice = 0;
-
- StringArray devices;
- snd_seq_t* const handle = iterateDevices (true, devices, deviceIndex);
-
- if (handle != 0)
- {
- newDevice = new MidiInput (devices [deviceIndex]);
- newDevice->internal = new MidiInputThread (newDevice, handle, callback);
- }
-
- return newDevice;
- }
-
- MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
- {
- MidiInput* newDevice = 0;
-
- snd_seq_t* const handle = createDevice (true, deviceName);
-
- if (handle != 0)
- {
- newDevice = new MidiInput (deviceName);
- newDevice->internal = new MidiInputThread (newDevice, handle, callback);
- }
-
- return newDevice;
- }
-
-
-
- END_JUCE_NAMESPACE
-
- //==============================================================================
-
- #else
-
- //==============================================================================
- // (These are just stub functions if ALSA is unavailable...)
-
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "../../../src/juce_appframework/audio/devices/juce_MidiOutput.h"
- #include "../../../src/juce_appframework/audio/devices/juce_MidiInput.h"
-
- //==============================================================================
- const StringArray MidiOutput::getDevices() { return StringArray(); }
- int MidiOutput::getDefaultDeviceIndex() { return 0; }
- MidiOutput* MidiOutput::openDevice (int) { return 0; }
- MidiOutput* MidiOutput::createNewDevice (const String&) { return 0; }
- MidiOutput::~MidiOutput() {}
- void MidiOutput::reset() {}
- bool MidiOutput::getVolume (float&, float&) { return false; }
- void MidiOutput::setVolume (float, float) {}
- void MidiOutput::sendMessageNow (const MidiMessage&) {}
-
- MidiInput::MidiInput (const String& name_)
- : name (name_),
- internal (0)
- {}
-
- MidiInput::~MidiInput() {}
- void MidiInput::start() {}
- void MidiInput::stop() {}
- int MidiInput::getDefaultDeviceIndex() { return 0; }
- const StringArray MidiInput::getDevices() { return StringArray(); }
- MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return 0; }
- MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return 0; }
-
- END_JUCE_NAMESPACE
-
- #endif
-
- #endif
|