@@ -32,10 +32,11 @@ struct MidiOutput::PendingMessage | |||
PendingMessage* next; | |||
}; | |||
MidiOutput::MidiOutput() | |||
MidiOutput::MidiOutput(const String& midiName) | |||
: Thread ("midi out"), | |||
internal (nullptr), | |||
firstMessage (nullptr) | |||
firstMessage (nullptr), | |||
name (midiName) | |||
{ | |||
} | |||
@@ -84,6 +84,9 @@ public: | |||
/** Destructor. */ | |||
~MidiOutput(); | |||
/** Returns the name of this device. */ | |||
const String& getName() const noexcept { return name; } | |||
/** Makes this device output a midi message. | |||
@see MidiMessage | |||
*/ | |||
@@ -131,8 +134,9 @@ private: | |||
CriticalSection lock; | |||
struct PendingMessage; | |||
PendingMessage* firstMessage; | |||
String name; | |||
MidiOutput(); // These objects are created with the openDevice() method. | |||
MidiOutput(const String& midiName); // These objects are created with the openDevice() method. | |||
void run() override; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) | |||
@@ -497,7 +497,7 @@ MidiOutput* MidiOutput::openDevice (int deviceIndex) | |||
if (port.isValid()) | |||
{ | |||
newDevice = new MidiOutput(); | |||
newDevice = new MidiOutput (devices [deviceIndex]); | |||
newDevice->internal = new MidiOutputDevice (newDevice, port); | |||
} | |||
@@ -512,7 +512,7 @@ MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
if (port.isValid()) | |||
{ | |||
newDevice = new MidiOutput(); | |||
newDevice = new MidiOutput (deviceName); | |||
newDevice->internal = new MidiOutputDevice (newDevice, port); | |||
} | |||
@@ -332,10 +332,11 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
{ | |||
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | |||
MIDIPortRef port; | |||
String deviceName = CoreMidiHelpers::getConnectedEndpointName (endPoint); | |||
if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname.cfString, &port))) | |||
{ | |||
mo = new MidiOutput(); | |||
mo = new MidiOutput (deviceName); | |||
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); | |||
} | |||
} | |||
@@ -354,7 +355,7 @@ MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name.cfString, &endPoint))) | |||
{ | |||
MidiOutput* mo = new MidiOutput(); | |||
MidiOutput* mo = new MidiOutput (deviceName); | |||
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); | |||
return mo; | |||
} | |||
@@ -362,6 +362,7 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
UINT deviceId = MIDI_MAPPER; | |||
const UINT num = midiOutGetNumDevs(); | |||
int n = 0; | |||
String deviceName; | |||
for (UINT i = 0; i < num; ++i) | |||
{ | |||
@@ -369,13 +370,16 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR) | |||
{ | |||
String name = String (mc.szPname, sizeof (mc.szPname)); | |||
// use the microsoft sw synth as a default - best not to allow deviceId | |||
// to be MIDI_MAPPER, or else device sharing breaks | |||
if (String (mc.szPname, sizeof (mc.szPname)).containsIgnoreCase ("microsoft")) | |||
if (name.containsIgnoreCase ("microsoft")) | |||
deviceId = i; | |||
if (index == n) | |||
{ | |||
deviceName = name; | |||
deviceId = i; | |||
break; | |||
} | |||
@@ -392,7 +396,7 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
{ | |||
han->refCount++; | |||
MidiOutput* const out = new MidiOutput(); | |||
MidiOutput* const out = new MidiOutput (deviceName); | |||
out->internal = han; | |||
return out; | |||
} | |||
@@ -411,7 +415,7 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
han->handle = h; | |||
MidiOutHandle::activeHandles.add (han); | |||
MidiOutput* const out = new MidiOutput(); | |||
MidiOutput* const out = new MidiOutput (deviceName); | |||
out->internal = han; | |||
return out; | |||
} | |||
@@ -244,7 +244,11 @@ void FLAC__cpu_info(FLAC__CPUInfo *info) | |||
struct sigaction sigill_save; | |||
struct sigaction sigill_sse; | |||
sigill_sse.sa_sigaction = sigill_handler_sse_os; | |||
#ifdef __ANDROID__ | |||
sigemptyset (&sigill_sse.sa_mask); | |||
#else | |||
__sigemptyset(&sigill_sse.sa_mask); | |||
#endif | |||
sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */ | |||
if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save)) | |||
{ | |||
@@ -521,14 +521,14 @@ public: | |||
: findNumInputChannels(); | |||
const size_t sizeInBytes = (sizeof (AudioChannelLayout) - sizeof (AudioChannelDescription)) + | |||
(numChannels * sizeof (AudioChannelDescription)); | |||
(static_cast<size_t> (numChannels) * sizeof (AudioChannelDescription)); | |||
if (outLayoutPtr != nullptr) | |||
{ | |||
zeromem (outLayoutPtr, sizeInBytes); | |||
outLayoutPtr->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; | |||
outLayoutPtr->mNumberChannelDescriptions = numChannels; | |||
outLayoutPtr->mNumberChannelDescriptions = static_cast<UInt32> (numChannels); | |||
for (int i = 0; i < numChannels; ++i) | |||
{ | |||
@@ -1121,7 +1121,8 @@ public: | |||
uridTimeBeatsPerMinute (0), | |||
uridTimeBeatUnit (0), | |||
uridTimeFrame (0), | |||
uridTimeSpeed (0) | |||
uridTimeSpeed (0), | |||
usingNominalBlockLength (false) | |||
{ | |||
filter = createPluginFilterOfType (AudioProcessor::wrapperType_VST); // FIXME | |||
jassert (filter != nullptr); | |||
@@ -1166,6 +1167,23 @@ public: | |||
if (uridMap != nullptr) | |||
{ | |||
uridAtomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank); | |||
uridAtomObject = uridMap->map(uridMap->handle, LV2_ATOM__Object); | |||
uridAtomDouble = uridMap->map(uridMap->handle, LV2_ATOM__Double); | |||
uridAtomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); | |||
uridAtomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int); | |||
uridAtomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long); | |||
uridAtomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence); | |||
uridMidiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); | |||
uridTimePos = uridMap->map(uridMap->handle, LV2_TIME__Position); | |||
uridTimeBar = uridMap->map(uridMap->handle, LV2_TIME__bar); | |||
uridTimeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat); | |||
uridTimeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar); | |||
uridTimeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute); | |||
uridTimeBeatUnit = uridMap->map(uridMap->handle, LV2_TIME__beatUnit); | |||
uridTimeFrame = uridMap->map(uridMap->handle, LV2_TIME__frame); | |||
uridTimeSpeed = uridMap->map(uridMap->handle, LV2_TIME__speed); | |||
for (int i=0; features[i] != nullptr; ++i) | |||
{ | |||
if (strcmp(features[i]->URI, LV2_OPTIONS__options) == 0) | |||
@@ -1176,34 +1194,31 @@ public: | |||
{ | |||
if (options[j].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) | |||
{ | |||
if (options[j].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | |||
if (options[j].type == uridAtomInt) | |||
{ | |||
bufferSize = *(int*)options[j].value; | |||
usingNominalBlockLength = true; | |||
} | |||
else | |||
{ | |||
std::cerr << "Host provides nominalBlockLength but has wrong value type" << std::endl; | |||
} | |||
break; | |||
} | |||
if (options[j].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) | |||
{ | |||
if (options[j].type == uridAtomInt) | |||
bufferSize = *(int*)options[j].value; | |||
else | |||
std::cerr << "Host provides maxBlockLength but has wrong value type" << std::endl; | |||
// no break, continue in case host supports nominalBlockLength | |||
} | |||
} | |||
break; | |||
} | |||
} | |||
uridAtomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank); | |||
uridAtomObject = uridMap->map(uridMap->handle, LV2_ATOM__Object); | |||
uridAtomDouble = uridMap->map(uridMap->handle, LV2_ATOM__Double); | |||
uridAtomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); | |||
uridAtomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int); | |||
uridAtomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long); | |||
uridAtomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence); | |||
uridMidiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); | |||
uridTimePos = uridMap->map(uridMap->handle, LV2_TIME__Position); | |||
uridTimeBar = uridMap->map(uridMap->handle, LV2_TIME__bar); | |||
uridTimeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat); | |||
uridTimeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar); | |||
uridTimeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute); | |||
uridTimeBeatUnit = uridMap->map(uridMap->handle, LV2_TIME__beatUnit); | |||
uridTimeFrame = uridMap->map(uridMap->handle, LV2_TIME__frame); | |||
uridTimeSpeed = uridMap->map(uridMap->handle, LV2_TIME__speed); | |||
} | |||
progDesc.bank = 0; | |||
@@ -1653,14 +1668,21 @@ public: | |||
{ | |||
if (options[j].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) | |||
{ | |||
if (options[j].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | |||
if (options[j].type == uridAtomInt) | |||
bufferSize = *(int*)options[j].value; | |||
else | |||
std::cerr << "Host changed nominalBlockLength but with wrong value type" << std::endl; | |||
} | |||
else if (options[j].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! usingNominalBlockLength) | |||
{ | |||
if (options[j].type == uridAtomInt) | |||
bufferSize = *(int*)options[j].value; | |||
else | |||
std::cerr << "Host changed maxBlockLength but with wrong value type" << std::endl; | |||
} | |||
else if (options[j].key == uridMap->map(uridMap->handle, LV2_CORE__sampleRate)) | |||
{ | |||
if (options[j].type == uridMap->map(uridMap->handle, LV2_ATOM__Double)) | |||
if (options[j].type == uridAtomDouble) | |||
sampleRate = *(double*)options[j].value; | |||
else | |||
std::cerr << "Host changed sampleRate but with wrong value type" << std::endl; | |||
@@ -1883,6 +1905,8 @@ private: | |||
LV2_URID uridTimeFrame; // timeInSamples | |||
LV2_URID uridTimeSpeed; | |||
bool usingNominalBlockLength; // if false use maxBlockLength | |||
LV2_Program_Descriptor progDesc; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLv2Wrapper) | |||
@@ -696,6 +696,29 @@ bool DatagramSocket::leaveMulticast (const String& multicastIPAddress) | |||
return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, false); | |||
} | |||
bool DatagramSocket::setEnablePortReuse (bool enabled) | |||
{ | |||
#if JUCE_ANDROID | |||
return false; | |||
#else | |||
const int reuse = enabled ? 1 : 0; | |||
#if JUCE_WINDOWS | |||
// port re-use is implied by addr re-use on windows | |||
const int optname = SO_REUSEADDR; | |||
#else | |||
const int optname = SO_REUSEPORT; | |||
#endif | |||
if (handle >= 0) | |||
return (setsockopt (handle, SOL_SOCKET, optname, | |||
(const char*) &reuse, sizeof (reuse)) == 0); | |||
return false; | |||
#endif | |||
} | |||
#if JUCE_MSVC | |||
#pragma warning (pop) | |||
#endif |
@@ -333,6 +333,17 @@ public: | |||
*/ | |||
bool leaveMulticast (const String& multicastIPAddress); | |||
//============================================================================== | |||
/** Allow other applications to re-use the port. | |||
Allow any other application currently running to bind to the same port. | |||
Do not use this if your socket handles sensitive data as it could be | |||
read by any, possibly malicious, third-party apps. | |||
Returns true on success. | |||
*/ | |||
bool setEnablePortReuse (bool enabled); | |||
private: | |||
//============================================================================== | |||
int handle; | |||
@@ -228,7 +228,7 @@ namespace juce | |||
//============================================================================== | |||
#if JUCE_MSVC && ! defined (DOXYGEN) | |||
#define JUCE_WARNING_HELPER(file, line, mess) message(file "(" JUCE_STRINGIFY (line) ") : Warning: " #mess) | |||
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message)); | |||
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message)) | |||
#else | |||
#ifndef DOXYGEN | |||
#define JUCE_WARNING_HELPER(mess) message(#mess) | |||
@@ -241,7 +241,7 @@ namespace juce | |||
GCC and Clang provide the \#warning directive, but MSVC doesn't, so this macro | |||
is a cross-compiler way to get the same functionality as \#warning. | |||
*/ | |||
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message))); | |||
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message))) | |||
#endif | |||
@@ -58,6 +58,13 @@ | |||
#undef Point | |||
#undef Component | |||
#if JUCE_PROJUCER_LIVE_BUILD | |||
// This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers | |||
// which cause some configurations of Clang to throw out an error.. | |||
#undef CF_OPTIONS | |||
#define CF_OPTIONS(_type, _name) _type _name; enum | |||
#endif | |||
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR | |||
#define JUCE_IPHONE 1 | |||
#define JUCE_IOS 1 | |||
@@ -42,6 +42,10 @@ namespace zlibNamespace | |||
#endif | |||
} | |||
#if ! defined (jmp_buf) || ! defined (longjmp) | |||
#include <setjmp.h> | |||
#endif | |||
namespace pnglibNamespace | |||
{ | |||
using namespace zlibNamespace; | |||
@@ -1091,6 +1091,11 @@ private: | |||
} | |||
//============================================================================== | |||
static bool isStartOfNumber (juce_wchar c) noexcept | |||
{ | |||
return CharacterFunctions::isDigit (c) || c == '-' || c == '+'; | |||
} | |||
static bool parseNextNumber (String::CharPointerType& text, String& value, const bool allowUnits) | |||
{ | |||
String::CharPointerType s (text); | |||
@@ -1100,14 +1105,21 @@ private: | |||
String::CharPointerType start (s); | |||
if (s.isDigit() || *s == '.' || *s == '-') | |||
if (isStartOfNumber (*s)) | |||
++s; | |||
while (s.isDigit()) | |||
++s; | |||
while (s.isDigit() || *s == '.') | |||
if (*s == '.') | |||
{ | |||
++s; | |||
if ((*s == 'e' || *s == 'E') | |||
&& ((s + 1).isDigit() || s[1] == '-' || s[1] == '+')) | |||
while (s.isDigit()) | |||
++s; | |||
} | |||
if ((*s == 'e' || *s == 'E') && isStartOfNumber (s[1])) | |||
{ | |||
s += 2; | |||
@@ -723,19 +723,19 @@ public: | |||
{ | |||
} | |||
bool perform() | |||
bool perform() override | |||
{ | |||
owner.insert (text, insertIndex, font, colour, 0, newCaretPos); | |||
return true; | |||
} | |||
bool undo() | |||
bool undo() override | |||
{ | |||
owner.remove (Range<int> (insertIndex, insertIndex + text.length()), 0, oldCaretPos); | |||
return true; | |||
} | |||
int getSizeInUnits() | |||
int getSizeInUnits() override | |||
{ | |||
return text.length() + 16; | |||
} | |||
@@ -767,20 +767,20 @@ public: | |||
removedSections.addArray (oldSections); | |||
} | |||
bool perform() | |||
bool perform() override | |||
{ | |||
owner.remove (range, 0, newCaretPos); | |||
return true; | |||
} | |||
bool undo() | |||
bool undo() override | |||
{ | |||
owner.reinsert (range.getStart(), removedSections); | |||
owner.moveCaretTo (oldCaretPos, false); | |||
return true; | |||
} | |||
int getSizeInUnits() | |||
int getSizeInUnits() override | |||
{ | |||
int n = 16; | |||
for (int i = removedSections.size(); --i >= 0;) | |||
@@ -807,21 +807,21 @@ public: | |||
{ | |||
} | |||
bool perform() | |||
bool perform() override | |||
{ | |||
owner.currentActionIndex++; | |||
owner.insert (text, insertPos, false); | |||
return true; | |||
} | |||
bool undo() | |||
bool undo() override | |||
{ | |||
owner.currentActionIndex--; | |||
owner.remove (insertPos, insertPos + text.length(), false); | |||
return true; | |||
} | |||
int getSizeInUnits() { return text.length() + 32; } | |||
int getSizeInUnits() override { return text.length() + 32; } | |||
private: | |||
CodeDocument& owner; | |||
@@ -902,21 +902,21 @@ public: | |||
{ | |||
} | |||
bool perform() | |||
bool perform() override | |||
{ | |||
owner.currentActionIndex++; | |||
owner.remove (startPos, endPos, false); | |||
return true; | |||
} | |||
bool undo() | |||
bool undo() override | |||
{ | |||
owner.currentActionIndex--; | |||
owner.insert (removedText, startPos, false); | |||
return true; | |||
} | |||
int getSizeInUnits() { return (endPos - startPos) + 32; } | |||
int getSizeInUnits() override { return (endPos - startPos) + 32; } | |||
private: | |||
CodeDocument& owner; | |||
@@ -287,7 +287,7 @@ public: | |||
private: | |||
#if JUCE_MAC | |||
WebView* webView; | |||
NSObject* clickListener; | |||
id clickListener; | |||
#else | |||
UIWebView* webView; | |||
WebViewTapDetector* tapDetector; | |||