@@ -25,9 +25,84 @@ | |||||
#if JUCE_ALSA | #if JUCE_ALSA | ||||
// You can define these strings in your app if you want to override the default names: | |||||
#ifndef JUCE_ALSA_MIDI_INPUT_NAME | |||||
#define JUCE_ALSA_MIDI_INPUT_NAME "Juce Midi Input" | |||||
#endif | |||||
#ifndef JUCE_ALSA_MIDI_OUTPUT_NAME | |||||
#define JUCE_ALSA_MIDI_OUTPUT_NAME "Juce Midi Output" | |||||
#endif | |||||
//============================================================================== | //============================================================================== | ||||
namespace | namespace | ||||
{ | { | ||||
snd_seq_t* iterateMidiClient (snd_seq_t* seqHandle, | |||||
snd_seq_client_info_t* clientInfo, | |||||
const bool forInput, | |||||
StringArray& deviceNamesFound, | |||||
const int deviceIndexToOpen) | |||||
{ | |||||
snd_seq_t* returnedHandle = nullptr; | |||||
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) | |||||
{ | |||||
if (forInput) | |||||
{ | |||||
snd_seq_set_client_name (seqHandle, JUCE_ALSA_MIDI_INPUT_NAME); | |||||
const int portId = snd_seq_create_simple_port (seqHandle, "Juce Midi In Port", | |||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, | |||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||||
snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort); | |||||
} | |||||
else | |||||
{ | |||||
snd_seq_set_client_name (seqHandle, JUCE_ALSA_MIDI_OUTPUT_NAME); | |||||
const int portId = snd_seq_create_simple_port (seqHandle, "Juce Midi Out Port", | |||||
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, | |||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||||
snd_seq_connect_to (seqHandle, portId, sourceClient, sourcePort); | |||||
} | |||||
returnedHandle = seqHandle; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
snd_seq_port_info_free (portInfo); | |||||
} | |||||
return returnedHandle; | |||||
} | |||||
snd_seq_t* iterateMidiDevices (const bool forInput, | snd_seq_t* iterateMidiDevices (const bool forInput, | ||||
StringArray& deviceNamesFound, | StringArray& deviceNamesFound, | ||||
const int deviceIndexToOpen) | const int deviceIndexToOpen) | ||||
@@ -49,65 +124,10 @@ namespace | |||||
int numClients = snd_seq_system_info_get_cur_clients (systemInfo); | int numClients = snd_seq_system_info_get_cur_clients (systemInfo); | ||||
while (--numClients >= 0 && returnedHandle == 0) | while (--numClients >= 0 && returnedHandle == 0) | ||||
{ | |||||
if (snd_seq_query_next_client (seqHandle, clientInfo) == 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) | |||||
{ | |||||
if (forInput) | |||||
{ | |||||
snd_seq_set_client_name (seqHandle, "Juce Midi Input"); | |||||
const int portId = snd_seq_create_simple_port (seqHandle, "Juce Midi In Port", | |||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, | |||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||||
snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort); | |||||
} | |||||
else | |||||
{ | |||||
snd_seq_set_client_name (seqHandle, "Juce Midi Output"); | |||||
const int portId = snd_seq_create_simple_port (seqHandle, "Juce Midi Out Port", | |||||
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, | |||||
SND_SEQ_PORT_TYPE_MIDI_GENERIC); | |||||
snd_seq_connect_to (seqHandle, portId, sourceClient, sourcePort); | |||||
} | |||||
returnedHandle = seqHandle; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
snd_seq_port_info_free (portInfo); | |||||
} | |||||
} | |||||
} | |||||
returnedHandle = iterateMidiClient (seqHandle, clientInfo, | |||||
forInput, deviceNamesFound, | |||||
deviceIndexToOpen); | |||||
snd_seq_client_info_free (clientInfo); | snd_seq_client_info_free (clientInfo); | ||||
} | } | ||||
@@ -139,7 +159,7 @@ namespace | |||||
forInput ? "in" | forInput ? "in" | ||||
: "out", | : "out", | ||||
forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE) | 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_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ), | |||||
forInput ? SND_SEQ_PORT_TYPE_APPLICATION | forInput ? SND_SEQ_PORT_TYPE_APPLICATION | ||||
: SND_SEQ_PORT_TYPE_MIDI_GENERIC); | : SND_SEQ_PORT_TYPE_MIDI_GENERIC); | ||||
@@ -1141,26 +1141,26 @@ bool AudioProcessorGraph::disconnectNode (const uint32 nodeId) | |||||
return doneAnything; | return doneAnything; | ||||
} | } | ||||
bool AudioProcessorGraph::isConnectionLegal (Connection* const c) const | |||||
{ | |||||
const Node* const source = getNodeForId (c->sourceNodeId); | |||||
const Node* const dest = getNodeForId (c->destNodeId); | |||||
return source != nullptr | |||||
&& dest != nullptr | |||||
&& (c->sourceChannelIndex != midiChannelIndex ? isPositiveAndBelow (c->sourceChannelIndex, source->processor->getNumOutputChannels()) | |||||
: source->processor->producesMidi()) | |||||
&& (c->destChannelIndex != midiChannelIndex ? isPositiveAndBelow (c->destChannelIndex, dest->processor->getNumInputChannels()) | |||||
: dest->processor->acceptsMidi()); | |||||
} | |||||
bool AudioProcessorGraph::removeIllegalConnections() | bool AudioProcessorGraph::removeIllegalConnections() | ||||
{ | { | ||||
bool doneAnything = false; | bool doneAnything = false; | ||||
for (int i = connections.size(); --i >= 0;) | for (int i = connections.size(); --i >= 0;) | ||||
{ | { | ||||
const Connection* const c = connections.getUnchecked(i); | |||||
const Node* const source = getNodeForId (c->sourceNodeId); | |||||
const Node* const dest = getNodeForId (c->destNodeId); | |||||
if (source == nullptr || dest == nullptr | |||||
|| (c->sourceChannelIndex != midiChannelIndex | |||||
&& ! isPositiveAndBelow (c->sourceChannelIndex, source->processor->getNumOutputChannels())) | |||||
|| (c->sourceChannelIndex == midiChannelIndex | |||||
&& ! source->processor->producesMidi()) | |||||
|| (c->destChannelIndex != midiChannelIndex | |||||
&& ! isPositiveAndBelow (c->destChannelIndex, dest->processor->getNumInputChannels())) | |||||
|| (c->destChannelIndex == midiChannelIndex | |||||
&& ! dest->processor->acceptsMidi())) | |||||
if (! isConnectionLegal (connections.getUnchecked(i))) | |||||
{ | { | ||||
removeConnection (i); | removeConnection (i); | ||||
doneAnything = true; | doneAnything = true; | ||||
@@ -245,6 +245,13 @@ public: | |||||
*/ | */ | ||||
bool disconnectNode (uint32 nodeId); | bool disconnectNode (uint32 nodeId); | ||||
/** Returns true if the given connection's channel numbers map on to valid | |||||
channels at each end. | |||||
Even if a connection is valid when created, its status could change if | |||||
a node changes its channel config. | |||||
*/ | |||||
bool isConnectionLegal (Connection* connection) const; | |||||
/** Performs a sanity checks of all the connections. | /** Performs a sanity checks of all the connections. | ||||
This might be useful if some of the processors are doing things like changing | This might be useful if some of the processors are doing things like changing | ||||
@@ -340,7 +340,7 @@ private: | |||||
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port) | static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port) | ||||
{ | { | ||||
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.1\r\nHost: " << host; | |||||
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host; | |||||
if (port > 0) | if (port > 0) | ||||
dest << ':' << port; | dest << ':' << port; | ||||
@@ -84,6 +84,20 @@ URL& URL::operator= (const URL& other) | |||||
return *this; | return *this; | ||||
} | } | ||||
bool URL::operator== (const URL& other) const | |||||
{ | |||||
return url == other.url | |||||
&& postData == other.postData | |||||
&& parameters == other.parameters | |||||
&& filesToUpload == other.filesToUpload | |||||
&& mimeTypes == other.mimeTypes; | |||||
} | |||||
bool URL::operator!= (const URL& other) const | |||||
{ | |||||
return ! operator== (other); | |||||
} | |||||
URL::~URL() | URL::~URL() | ||||
{ | { | ||||
} | } | ||||
@@ -58,6 +58,13 @@ public: | |||||
/** Copies this URL from another one. */ | /** Copies this URL from another one. */ | ||||
URL& operator= (const URL& other); | URL& operator= (const URL& other); | ||||
/** Compares two URLs. | |||||
All aspects of the URLs must be identical for them to match, including any parameters, | |||||
upload files, etc. | |||||
*/ | |||||
bool operator== (const URL&) const; | |||||
bool operator!= (const URL&) const; | |||||
//============================================================================== | //============================================================================== | ||||
/** Returns a string version of the URL. | /** Returns a string version of the URL. | ||||
@@ -309,7 +316,6 @@ private: | |||||
OpenStreamProgressCallback* progressCallback, | OpenStreamProgressCallback* progressCallback, | ||||
void* progressCallbackContext, const String& headers, | void* progressCallbackContext, const String& headers, | ||||
const int timeOutMs, StringPairArray* responseHeaders); | const int timeOutMs, StringPairArray* responseHeaders); | ||||
JUCE_LEAK_DETECTOR (URL); | JUCE_LEAK_DETECTOR (URL); | ||||
}; | }; | ||||
@@ -990,7 +990,7 @@ struct WildCardMatcher | |||||
{ | { | ||||
for (;;) | for (;;) | ||||
{ | { | ||||
const juce_wchar wc = *wildcard; | |||||
const juce_wchar wc = wildcard.getAndAdvance(); | |||||
const juce_wchar tc = *test; | const juce_wchar tc = *test; | ||||
if (wc == tc | if (wc == tc | ||||
@@ -1001,11 +1001,10 @@ struct WildCardMatcher | |||||
return true; | return true; | ||||
++test; | ++test; | ||||
++wildcard; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
return wc == '*' && (wildcard[1] == 0 || matchesAnywhere (wildcard + 1, test, ignoreCase)); | |||||
return wc == '*' && (wildcard.isEmpty() || matchesAnywhere (wildcard, test, ignoreCase)); | |||||
} | } | ||||
} | } | ||||
} | } | ||||