@@ -120,7 +120,7 @@ public: | |||
bool isRecording() const | |||
{ | |||
return activeWriter != nullptr; | |||
return activeWriter.load() != nullptr; | |||
} | |||
//============================================================================== | |||
@@ -140,9 +140,9 @@ public: | |||
{ | |||
const ScopedLock sl (writerLock); | |||
if (activeWriter != nullptr && numInputChannels >= thumbnail.getNumChannels()) | |||
if (activeWriter.load() != nullptr && numInputChannels >= thumbnail.getNumChannels()) | |||
{ | |||
activeWriter->write (inputChannelData, numSamples); | |||
activeWriter.load()->write (inputChannelData, numSamples); | |||
// Create an AudioBuffer to wrap our incoming data, note that this does no allocations or copies, it simply references our input data | |||
AudioBuffer<float> buffer (const_cast<float**> (inputChannelData), thumbnail.getNumChannels(), numSamples); | |||
@@ -158,13 +158,13 @@ public: | |||
private: | |||
AudioThumbnail& thumbnail; | |||
TimeSliceThread backgroundThread { "Audio Recorder Thread" }; // the thread that will write our audio data to disk | |||
TimeSliceThread backgroundThread { "Audio Recorder Thread" }; // the thread that will write our audio data to disk | |||
std::unique_ptr<AudioFormatWriter::ThreadedWriter> threadedWriter; // the FIFO used to buffer the incoming data | |||
double sampleRate = 0.0; | |||
double sampleRate = 0.0; | |||
int64 nextSampleNum = 0; | |||
CriticalSection writerLock; | |||
AudioFormatWriter::ThreadedWriter* volatile activeWriter = nullptr; | |||
std::atomic<AudioFormatWriter::ThreadedWriter*> activeWriter { nullptr }; | |||
}; | |||
//============================================================================== | |||
@@ -25,20 +25,14 @@ namespace juce | |||
BufferingAudioSource::BufferingAudioSource (PositionableAudioSource* s, | |||
TimeSliceThread& thread, | |||
const bool deleteSourceWhenDeleted, | |||
const int bufferSizeSamples, | |||
const int numChannels, | |||
bool deleteSourceWhenDeleted, | |||
int bufferSizeSamples, | |||
int numChannels, | |||
bool prefillBufferOnPrepareToPlay) | |||
: source (s, deleteSourceWhenDeleted), | |||
backgroundThread (thread), | |||
numberOfSamplesToBuffer (jmax (1024, bufferSizeSamples)), | |||
numberOfChannels (numChannels), | |||
bufferValidStart (0), | |||
bufferValidEnd (0), | |||
nextPlayPos (0), | |||
sampleRate (0), | |||
wasSourceLooping (false), | |||
isPrepared (false), | |||
prefillBuffer (prefillBufferOnPrepareToPlay) | |||
{ | |||
jassert (source != nullptr); | |||
@@ -55,7 +49,7 @@ BufferingAudioSource::~BufferingAudioSource() | |||
//============================================================================== | |||
void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double newSampleRate) | |||
{ | |||
const int bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); | |||
auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); | |||
if (newSampleRate != sampleRate | |||
|| bufferSizeNeeded != buffer.getNumSamples() | |||
@@ -104,8 +98,12 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info | |||
{ | |||
const ScopedLock sl (bufferStartPosLock); | |||
const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); | |||
const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); | |||
auto start = bufferValidStart.load(); | |||
auto end = bufferValidEnd.load(); | |||
auto pos = nextPlayPos.load(); | |||
auto validStart = (int) (jlimit (start, end, pos) - pos); | |||
auto validEnd = (int) (jlimit (start, end, pos + info.numSamples) - pos); | |||
if (validStart == validEnd) | |||
{ | |||
@@ -126,8 +124,8 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info | |||
for (int chan = jmin (numberOfChannels, info.buffer->getNumChannels()); --chan >= 0;) | |||
{ | |||
jassert (buffer.getNumSamples() > 0); | |||
const int startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); | |||
const int endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); | |||
auto startBufferIndex = (int) ((validStart + nextPlayPos) % buffer.getNumSamples()); | |||
auto endBufferIndex = (int) ((validEnd + nextPlayPos) % buffer.getNumSamples()); | |||
if (startBufferIndex < endBufferIndex) | |||
{ | |||
@@ -138,7 +136,7 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info | |||
} | |||
else | |||
{ | |||
const int initialSize = buffer.getNumSamples() - startBufferIndex; | |||
auto initialSize = buffer.getNumSamples() - startBufferIndex; | |||
info.buffer->copyFrom (chan, info.startSample + validStart, | |||
buffer, | |||
@@ -157,7 +155,7 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info | |||
} | |||
} | |||
bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, const uint32 timeout) | |||
bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelInfo& info, uint32 timeout) | |||
{ | |||
if (!source || source->getTotalLength() <= 0) | |||
return false; | |||
@@ -168,26 +166,28 @@ bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelI | |||
if (! isLooping() && nextPlayPos > getTotalLength()) | |||
return true; | |||
uint32 now = Time::getMillisecondCounter(); | |||
const uint32 startTime = now; | |||
auto now = Time::getMillisecondCounter(); | |||
auto startTime = now; | |||
uint32 elapsed = (now >= startTime ? now - startTime | |||
: (std::numeric_limits<uint32>::max() - startTime) + now); | |||
auto elapsed = (now >= startTime ? now - startTime | |||
: (std::numeric_limits<uint32>::max() - startTime) + now); | |||
while (elapsed <= timeout) | |||
{ | |||
{ | |||
const ScopedLock sl (bufferStartPosLock); | |||
const int validStart = static_cast<int> (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos); | |||
const int validEnd = static_cast<int> (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos); | |||
auto start = bufferValidStart.load(); | |||
auto end = bufferValidEnd.load(); | |||
auto pos = nextPlayPos.load(); | |||
auto validStart = static_cast<int> (jlimit (start, end, pos) - pos); | |||
auto validEnd = static_cast<int> (jlimit (start, end, pos + info.numSamples) - pos); | |||
if (validStart <= 0 && validStart < validEnd && validEnd >= info.numSamples) | |||
return true; | |||
} | |||
if (elapsed < timeout && (! bufferReadyEvent.wait (static_cast<int> (timeout - elapsed)))) | |||
return false; | |||
@@ -202,9 +202,11 @@ bool BufferingAudioSource::waitForNextAudioBlockReady (const AudioSourceChannelI | |||
int64 BufferingAudioSource::getNextReadPosition() const | |||
{ | |||
jassert (source->getTotalLength() > 0); | |||
auto pos = nextPlayPos.load(); | |||
return (source->isLooping() && nextPlayPos > 0) | |||
? nextPlayPos % source->getTotalLength() | |||
: nextPlayPos; | |||
? pos % source->getTotalLength() | |||
: pos; | |||
} | |||
void BufferingAudioSource::setNextReadPosition (int64 newPosition) | |||
@@ -229,7 +231,7 @@ bool BufferingAudioSource::readNextBufferChunk() | |||
bufferValidEnd = 0; | |||
} | |||
newBVS = jmax ((int64) 0, nextPlayPos); | |||
newBVS = jmax ((int64) 0, nextPlayPos.load()); | |||
newBVE = newBVS + buffer.getNumSamples() - 4; | |||
sectionToReadStart = 0; | |||
sectionToReadEnd = 0; | |||
@@ -255,7 +257,7 @@ bool BufferingAudioSource::readNextBufferChunk() | |||
sectionToReadEnd = newBVE; | |||
bufferValidStart = newBVS; | |||
bufferValidEnd = jmin (bufferValidEnd, newBVE); | |||
bufferValidEnd = jmin (bufferValidEnd.load(), newBVE); | |||
} | |||
} | |||
@@ -263,8 +265,8 @@ bool BufferingAudioSource::readNextBufferChunk() | |||
return false; | |||
jassert (buffer.getNumSamples() > 0); | |||
const int bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); | |||
const int bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); | |||
auto bufferIndexStart = (int) (sectionToReadStart % buffer.getNumSamples()); | |||
auto bufferIndexEnd = (int) (sectionToReadEnd % buffer.getNumSamples()); | |||
if (bufferIndexStart < bufferIndexEnd) | |||
{ | |||
@@ -274,7 +276,7 @@ bool BufferingAudioSource::readNextBufferChunk() | |||
} | |||
else | |||
{ | |||
const int initialSize = buffer.getNumSamples() - bufferIndexStart; | |||
auto initialSize = buffer.getNumSamples() - bufferIndexStart; | |||
readBufferSection (sectionToReadStart, | |||
initialSize, | |||
@@ -293,11 +295,10 @@ bool BufferingAudioSource::readNextBufferChunk() | |||
} | |||
bufferReadyEvent.signal(); | |||
return true; | |||
} | |||
void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset) | |||
void BufferingAudioSource::readBufferSection (int64 start, int length, int bufferOffset) | |||
{ | |||
if (source->getNextReadPosition() != start) | |||
source->setNextReadPosition (start); | |||
@@ -105,9 +105,9 @@ private: | |||
AudioBuffer<float> buffer; | |||
CriticalSection bufferStartPosLock; | |||
WaitableEvent bufferReadyEvent; | |||
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos; | |||
double volatile sampleRate; | |||
bool wasSourceLooping, isPrepared, prefillBuffer; | |||
std::atomic<int64> bufferValidStart { 0 }, bufferValidEnd { 0 }, nextPlayPos { 0 }; | |||
double sampleRate = 0; | |||
bool wasSourceLooping = false, isPrepared = false, prefillBuffer; | |||
bool readNextBufferChunk(); | |||
void readBufferSection (int64 start, int length, int bufferOffset); | |||
@@ -66,7 +66,7 @@ private: | |||
CriticalSection lock; | |||
OptionalScopedPointer<AudioSource> input; | |||
Reverb reverb; | |||
volatile bool bypass; | |||
std::atomic<bool> bypass; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource) | |||
}; | |||
@@ -29,7 +29,7 @@ namespace juce | |||
namespace CoreMidiHelpers | |||
{ | |||
static bool checkError (const OSStatus err, const int lineNum) | |||
static bool checkError (OSStatus err, int lineNum) | |||
{ | |||
if (err == noErr) | |||
return true; | |||
@@ -48,10 +48,10 @@ namespace CoreMidiHelpers | |||
//============================================================================== | |||
struct ScopedCFString | |||
{ | |||
ScopedCFString() noexcept : cfString (nullptr) {} | |||
ScopedCFString() noexcept {} | |||
~ScopedCFString() noexcept { if (cfString != nullptr) CFRelease (cfString); } | |||
CFStringRef cfString; | |||
CFStringRef cfString = {}; | |||
}; | |||
static String getMidiObjectName (MIDIObjectRef entity) | |||
@@ -87,7 +87,7 @@ namespace CoreMidiHelpers | |||
static String getEndpointName (MIDIEndpointRef endpoint, bool isExternal) | |||
{ | |||
String result (getMidiObjectName (endpoint)); | |||
auto result = getMidiObjectName (endpoint); | |||
MIDIEntityRef entity = 0; // NB: don't attempt to use nullptr for refs - it fails in some types of build. | |||
MIDIEndpointGetEntity (endpoint, &entity); | |||
@@ -104,7 +104,7 @@ namespace CoreMidiHelpers | |||
if (device != 0) | |||
{ | |||
const String deviceName (getMidiObjectName (device)); | |||
auto deviceName = getMidiObjectName (device); | |||
if (deviceName.isNotEmpty()) | |||
{ | |||
@@ -141,14 +141,14 @@ namespace CoreMidiHelpers | |||
if (numConnections > 0) | |||
{ | |||
const SInt32* pid = reinterpret_cast<const SInt32*> (CFDataGetBytePtr (connections)); | |||
auto pid = reinterpret_cast<const SInt32*> (CFDataGetBytePtr (connections)); | |||
for (int i = 0; i < numConnections; ++i, ++pid) | |||
{ | |||
MIDIUniqueID uid = (MIDIUniqueID) ByteOrder::swapIfLittleEndian ((uint32) *pid); | |||
auto uid = (MIDIUniqueID) ByteOrder::swapIfLittleEndian ((uint32) *pid); | |||
MIDIObjectRef connObject; | |||
MIDIObjectType connObjectType; | |||
OSStatus err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); | |||
auto err = MIDIObjectFindByUniqueID (uid, &connObject, &connObjectType); | |||
if (err == noErr) | |||
{ | |||
@@ -192,11 +192,12 @@ namespace CoreMidiHelpers | |||
#if defined (JucePlugin_CFBundleIdentifier) | |||
portUniqueId = JUCE_STRINGIFY (JucePlugin_CFBundleIdentifier); | |||
#else | |||
File appBundle (File::getSpecialLocation (File::currentApplicationFile)); | |||
CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, appBundle.getFullPathName().toCFString(), kCFURLPOSIXPathStyle, true); | |||
if (bundleURL != nullptr) | |||
auto appBundle = File::getSpecialLocation (File::currentApplicationFile); | |||
if (auto bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, appBundle.getFullPathName().toCFString(), | |||
kCFURLPOSIXPathStyle, true)) | |||
{ | |||
CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, bundleURL); | |||
auto bundleRef = CFBundleCreate (kCFAllocatorDefault, bundleURL); | |||
CFRelease (bundleURL); | |||
if (bundleRef != nullptr) | |||
@@ -211,31 +212,30 @@ namespace CoreMidiHelpers | |||
if (portUniqueId.isNotEmpty()) | |||
{ | |||
portUniqueId += (String ("." + portName + String (isInput ? ".input" : ".output"))); | |||
portUniqueId += "." + portName + (isInput ? ".input" : ".output"); | |||
CHECK_ERROR (MIDIObjectSetStringProperty (device, kMIDIPropertyUniqueID, portUniqueId.toCFString())); | |||
} | |||
} | |||
static StringArray findDevices (const bool forInput) | |||
static StringArray findDevices (bool forInput) | |||
{ | |||
// It seems that OSX can be a bit picky about the thread that's first used to | |||
// search for devices. It's safest to use the message thread for calling this. | |||
jassert (MessageManager::getInstance()->isThisTheMessageThread()); | |||
StringArray s; | |||
enableSimulatorMidiSession(); | |||
const ItemCount num = forInput ? MIDIGetNumberOfSources() | |||
: MIDIGetNumberOfDestinations(); | |||
StringArray s; | |||
auto num = forInput ? MIDIGetNumberOfSources() | |||
: MIDIGetNumberOfDestinations(); | |||
for (ItemCount i = 0; i < num; ++i) | |||
{ | |||
MIDIEndpointRef dest = forInput ? MIDIGetSource (i) | |||
: MIDIGetDestination (i); | |||
String name; | |||
if (dest != 0) | |||
if (auto dest = forInput ? MIDIGetSource (i) | |||
: MIDIGetDestination (i)) | |||
name = getConnectedEndpointName (dest); | |||
if (name.isEmpty()) | |||
@@ -298,7 +298,7 @@ namespace CoreMidiHelpers | |||
MIDIEndpointDispose (endPoint); | |||
} | |||
void send (const MIDIPacketList* const packets) noexcept | |||
void send (const MIDIPacketList* packets) noexcept | |||
{ | |||
if (port != 0) | |||
MIDISend (port, endPoint, packets); | |||
@@ -311,16 +311,13 @@ namespace CoreMidiHelpers | |||
}; | |||
//============================================================================== | |||
class MidiPortAndCallback; | |||
struct MidiPortAndCallback; | |||
CriticalSection callbackLock; | |||
Array<MidiPortAndCallback*> activeCallbacks; | |||
class MidiPortAndCallback | |||
struct MidiPortAndCallback | |||
{ | |||
public: | |||
MidiPortAndCallback (MidiInputCallback& cb) : callback (cb) | |||
{ | |||
} | |||
MidiPortAndCallback (MidiInputCallback& cb) : callback (cb) {} | |||
~MidiPortAndCallback() | |||
{ | |||
@@ -335,7 +332,7 @@ namespace CoreMidiHelpers | |||
CHECK_ERROR (MIDIPortDisconnectSource (portAndEndpoint->port, portAndEndpoint->endPoint)); | |||
} | |||
void handlePackets (const MIDIPacketList* const pktlist) | |||
void handlePackets (const MIDIPacketList* pktlist) | |||
{ | |||
auto time = Time::getMillisecondCounterHiRes() * 0.001; | |||
@@ -357,7 +354,7 @@ namespace CoreMidiHelpers | |||
MidiInput* input = nullptr; | |||
std::unique_ptr<MidiPortAndEndpoint> portAndEndpoint; | |||
volatile bool active = false; | |||
std::atomic<bool> active { false }; | |||
private: | |||
MidiInputCallback& callback; | |||
@@ -380,15 +377,15 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
if (isPositiveAndBelow (index, MIDIGetNumberOfDestinations())) | |||
{ | |||
MIDIEndpointRef endPoint = MIDIGetDestination ((ItemCount) index); | |||
auto endPoint = MIDIGetDestination ((ItemCount) index); | |||
CoreMidiHelpers::ScopedCFString pname; | |||
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname.cfString))) | |||
{ | |||
MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | |||
auto client = CoreMidiHelpers::getGlobalMidiClient(); | |||
MIDIPortRef port; | |||
String deviceName = CoreMidiHelpers::getConnectedEndpointName (endPoint); | |||
auto deviceName = CoreMidiHelpers::getConnectedEndpointName (endPoint); | |||
if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname.cfString, &port))) | |||
{ | |||
@@ -413,7 +410,7 @@ MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
{ | |||
CoreMidiHelpers::setUniqueIdForMidiPort (endPoint, deviceName, false); | |||
MidiOutput* mo = new MidiOutput (deviceName); | |||
auto mo = new MidiOutput (deviceName); | |||
mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); | |||
return mo; | |||
} | |||
@@ -438,8 +435,8 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
HeapBlock<MIDIPacketList> allocatedPackets; | |||
MIDIPacketList stackPacket; | |||
MIDIPacketList* packetToSend = &stackPacket; | |||
const size_t dataSize = (size_t) message.getRawDataSize(); | |||
auto* packetToSend = &stackPacket; | |||
auto dataSize = (size_t) message.getRawDataSize(); | |||
if (message.isSysEx()) | |||
{ | |||
@@ -450,7 +447,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
packetToSend = allocatedPackets; | |||
packetToSend->numPackets = (UInt32) numPackets; | |||
MIDIPacket* p = packetToSend->packet; | |||
auto* p = packetToSend->packet; | |||
for (int i = 0; i < numPackets; ++i) | |||
{ | |||
@@ -464,7 +461,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
} | |||
else if (dataSize < 65536) // max packet size | |||
{ | |||
const size_t stackCapacity = sizeof (stackPacket.packet->data); | |||
auto stackCapacity = sizeof (stackPacket.packet->data); | |||
if (dataSize > stackCapacity) | |||
{ | |||
@@ -473,7 +470,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
} | |||
packetToSend->numPackets = 1; | |||
MIDIPacket& p = *(packetToSend->packet); | |||
auto& p = *(packetToSend->packet); | |||
p.timeStamp = timeStamp; | |||
p.length = (UInt16) dataSize; | |||
memcpy (p.data, message.getRawData(), dataSize); | |||
@@ -500,13 +497,13 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) | |||
if (isPositiveAndBelow (index, MIDIGetNumberOfSources())) | |||
{ | |||
if (MIDIEndpointRef endPoint = MIDIGetSource ((ItemCount) index)) | |||
if (auto endPoint = MIDIGetSource ((ItemCount) index)) | |||
{ | |||
ScopedCFString name; | |||
if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name.cfString))) | |||
{ | |||
if (MIDIClientRef client = getGlobalMidiClient()) | |||
if (auto client = getGlobalMidiClient()) | |||
{ | |||
MIDIPortRef port; | |||
std::unique_ptr<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||
@@ -540,11 +537,9 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) | |||
MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback) | |||
{ | |||
jassert (callback != nullptr); | |||
using namespace CoreMidiHelpers; | |||
MidiInput* mi = nullptr; | |||
if (MIDIClientRef client = getGlobalMidiClient()) | |||
if (auto client = getGlobalMidiClient()) | |||
{ | |||
std::unique_ptr<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||
mpc->active = false; | |||
@@ -555,20 +550,22 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba | |||
if (CHECK_ERROR (MIDIDestinationCreate (client, name.cfString, midiInputProc, mpc.get(), &endPoint))) | |||
{ | |||
CoreMidiHelpers::setUniqueIdForMidiPort (endPoint, deviceName, true); | |||
setUniqueIdForMidiPort (endPoint, deviceName, true); | |||
mpc->portAndEndpoint.reset (new MidiPortAndEndpoint (0, endPoint)); | |||
mi = new MidiInput (deviceName); | |||
auto mi = new MidiInput (deviceName); | |||
mpc->input = mi; | |||
mi->internal = mpc.get(); | |||
const ScopedLock sl (callbackLock); | |||
activeCallbacks.add (mpc.release()); | |||
return mi; | |||
} | |||
} | |||
return mi; | |||
return nullptr; | |||
} | |||
MidiInput::MidiInput (const String& nm) : name (nm) | |||
@@ -77,11 +77,7 @@ struct ASIOSampleFormat | |||
{ | |||
ASIOSampleFormat() noexcept {} | |||
ASIOSampleFormat (const long type) noexcept | |||
: bitDepth (24), | |||
littleEndian (true), | |||
formatIsFloat (false), | |||
byteStride (4) | |||
ASIOSampleFormat (long type) noexcept | |||
{ | |||
switch (type) | |||
{ | |||
@@ -114,7 +110,7 @@ struct ASIOSampleFormat | |||
} | |||
} | |||
void convertToFloat (const void* const src, float* const dst, const int samps) const noexcept | |||
void convertToFloat (const void* src, float* dst, int samps) const noexcept | |||
{ | |||
if (formatIsFloat) | |||
{ | |||
@@ -132,7 +128,7 @@ struct ASIOSampleFormat | |||
} | |||
} | |||
void convertFromFloat (const float* const src, void* const dst, const int samps) const noexcept | |||
void convertFromFloat (const float* src, void* dst, int samps) const noexcept | |||
{ | |||
if (formatIsFloat) | |||
{ | |||
@@ -150,18 +146,18 @@ struct ASIOSampleFormat | |||
} | |||
} | |||
void clear (void* dst, const int numSamps) noexcept | |||
void clear (void* dst, int numSamps) noexcept | |||
{ | |||
if (dst != nullptr) | |||
zeromem (dst, numSamps * byteStride); | |||
} | |||
int bitDepth, byteStride; | |||
bool formatIsFloat, littleEndian; | |||
int bitDepth = 24, byteStride = 4; | |||
bool formatIsFloat = false, littleEndian = true; | |||
private: | |||
static void convertInt16ToFloat (const char* src, float* dest, const int srcStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertInt16ToFloat (const char* src, float* dest, int srcStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double g = 1.0 / 32768.0; | |||
@@ -183,8 +179,8 @@ private: | |||
} | |||
} | |||
static void convertFloatToInt16 (const float* src, char* dest, const int dstStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertFloatToInt16 (const float* src, char* dest, int dstStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double maxVal = (double) 0x7fff; | |||
@@ -206,8 +202,8 @@ private: | |||
} | |||
} | |||
static void convertInt24ToFloat (const char* src, float* dest, const int srcStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertInt24ToFloat (const char* src, float* dest, int srcStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double g = 1.0 / 0x7fffff; | |||
@@ -229,8 +225,8 @@ private: | |||
} | |||
} | |||
static void convertFloatToInt24 (const float* src, char* dest, const int dstStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertFloatToInt24 (const float* src, char* dest, int dstStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double maxVal = (double) 0x7fffff; | |||
@@ -252,8 +248,8 @@ private: | |||
} | |||
} | |||
static void convertInt32ToFloat (const char* src, float* dest, const int srcStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertInt32ToFloat (const char* src, float* dest, int srcStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double g = 1.0 / 0x7fffffff; | |||
@@ -275,8 +271,8 @@ private: | |||
} | |||
} | |||
static void convertFloatToInt32 (const float* src, char* dest, const int dstStrideBytes, | |||
int numSamples, const bool littleEndian) noexcept | |||
static void convertFloatToInt32 (const float* src, char* dest, int dstStrideBytes, | |||
int numSamples, bool littleEndian) noexcept | |||
{ | |||
const double maxVal = (double) 0x7fffffff; | |||
@@ -300,8 +296,9 @@ private: | |||
}; | |||
//============================================================================== | |||
constexpr int maxNumASIODevices = 16; | |||
class ASIOAudioIODevice; | |||
static ASIOAudioIODevice* volatile currentASIODev[16] = { 0 }; | |||
static ASIOAudioIODevice* currentASIODev[maxNumASIODevices] = {}; | |||
extern HWND juce_messageWindowHandle; | |||
@@ -314,33 +311,10 @@ class ASIOAudioIODevice : public AudioIODevice, | |||
{ | |||
public: | |||
ASIOAudioIODevice (ASIOAudioIODeviceType* ownerType, const String& devName, | |||
const CLSID clsID, const int slotNumber) | |||
CLSID clsID, int slotNumber) | |||
: AudioIODevice (devName, "ASIO"), | |||
owner (ownerType), | |||
asioObject (nullptr), | |||
classId (clsID), | |||
inputLatency (0), | |||
outputLatency (0), | |||
minBufferSize (0), maxBufferSize (0), | |||
preferredBufferSize (0), | |||
bufferGranularity (0), | |||
numClockSources (0), | |||
currentBlockSizeSamples (0), | |||
currentBitDepth (16), | |||
currentSampleRate (0), | |||
currentCallback (nullptr), | |||
bufferIndex (0), | |||
numActiveInputChans (0), | |||
numActiveOutputChans (0), | |||
deviceIsOpen (false), | |||
isStarted (false), | |||
buffersCreated (false), | |||
calledback (false), | |||
littleEndian (false), | |||
postOutput (true), | |||
needToReset (false), | |||
insideControlPanelModalLoop (false), | |||
shouldUsePreferredSize (false) | |||
classId (clsID) | |||
{ | |||
::CoInitialize (nullptr); | |||
@@ -348,15 +322,15 @@ public: | |||
inBuffers.calloc (4); | |||
outBuffers.calloc (4); | |||
jassert (currentASIODev [slotNumber] == nullptr); | |||
currentASIODev [slotNumber] = this; | |||
jassert (currentASIODev[slotNumber] == nullptr); | |||
currentASIODev[slotNumber] = this; | |||
openDevice(); | |||
} | |||
~ASIOAudioIODevice() | |||
{ | |||
for (int i = 0; i < numElementsInArray (currentASIODev); ++i) | |||
for (int i = 0; i < maxNumASIODevices; ++i) | |||
if (currentASIODev[i] == this) | |||
currentASIODev[i] = nullptr; | |||
@@ -381,7 +355,7 @@ public: | |||
if (newRates.isEmpty()) | |||
{ | |||
double cr = getSampleRate(); | |||
auto cr = getSampleRate(); | |||
JUCE_ASIO_LOG ("No sample rates supported - current rate: " + String ((int) cr)); | |||
if (cr > 0) | |||
@@ -394,8 +368,9 @@ public: | |||
#if JUCE_ASIO_DEBUGGING | |||
StringArray s; | |||
for (int i = 0; i < sampleRates.size(); ++i) | |||
s.add (String (sampleRates.getUnchecked(i))); | |||
for (auto r : sampleRates) | |||
s.add (String (r)); | |||
JUCE_ASIO_LOG ("Rates: " + s.joinIntoString (" ")); | |||
#endif | |||
@@ -425,21 +400,20 @@ public: | |||
if (asioObject == nullptr) | |||
{ | |||
const String openingError (openDevice()); | |||
auto openingError = openDevice(); | |||
if (asioObject == nullptr) | |||
return openingError; | |||
} | |||
isStarted = false; | |||
bufferIndex = -1; | |||
long err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans); | |||
auto err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans); | |||
jassert (err == ASE_OK); | |||
bufferSizeSamples = readBufferSizes (bufferSizeSamples); | |||
double sampleRate = sr; | |||
auto sampleRate = sr; | |||
currentSampleRate = sampleRate; | |||
currentBlockSizeSamples = bufferSizeSamples; | |||
currentChansOut.clear(); | |||
@@ -450,9 +424,11 @@ public: | |||
if (sampleRate == 0 || (sampleRates.size() > 0 && ! sampleRates.contains (sampleRate))) | |||
sampleRate = sampleRates[0]; | |||
jassert (sampleRate != 0); | |||
if (sampleRate == 0) | |||
{ | |||
jassertfalse; | |||
sampleRate = 44100.0; | |||
} | |||
updateClockSources(); | |||
currentSampleRate = getSampleRate(); | |||
@@ -486,7 +462,7 @@ public: | |||
needToReset = false; | |||
} | |||
const int totalBuffers = resetBuffers (inputChannels, outputChannels); | |||
auto totalBuffers = resetBuffers (inputChannels, outputChannels); | |||
setCallbackFunctions(); | |||
@@ -508,7 +484,7 @@ public: | |||
if (err == ASE_OK) | |||
{ | |||
buffersCreated = true; | |||
tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32); | |||
ioBufferSpace.calloc (totalBuffers * currentBlockSizeSamples + 32); | |||
int n = 0; | |||
Array<int> types; | |||
@@ -518,7 +494,7 @@ public: | |||
{ | |||
if (inputChannels[i]) | |||
{ | |||
inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n); | |||
inBuffers[n] = ioBufferSpace + (currentBlockSizeSamples * n); | |||
ASIOChannelInfo channelInfo = { 0 }; | |||
channelInfo.channel = i; | |||
@@ -540,7 +516,7 @@ public: | |||
{ | |||
if (outputChannels[i]) | |||
{ | |||
outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n)); | |||
outBuffers[n] = ioBufferSpace + (currentBlockSizeSamples * (numActiveInputChans + n)); | |||
ASIOChannelInfo channelInfo = { 0 }; | |||
channelInfo.channel = i; | |||
@@ -564,8 +540,8 @@ public: | |||
for (int i = 0; i < numActiveOutputChans; ++i) | |||
{ | |||
outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[0], currentBlockSizeSamples); | |||
outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[1], currentBlockSizeSamples); | |||
outputFormat[i].clear (bufferInfos[numActiveInputChans + i].buffers[0], currentBlockSizeSamples); | |||
outputFormat[i].clear (bufferInfos[numActiveInputChans + i].buffers[1], currentBlockSizeSamples); | |||
} | |||
readLatencies(); | |||
@@ -615,7 +591,7 @@ public: | |||
isStarted = false; | |||
deviceIsOpen = false; | |||
const String errorCopy (error); | |||
auto errorCopy = error; | |||
close(); // (this resets the error string) | |||
error = errorCopy; | |||
} | |||
@@ -678,7 +654,7 @@ public: | |||
void stop() override | |||
{ | |||
AudioIODeviceCallback* const lastCallback = currentCallback; | |||
auto* lastCallback = currentCallback; | |||
{ | |||
const ScopedLock sl (callbackLock); | |||
@@ -698,15 +674,13 @@ public: | |||
bool done = false; | |||
insideControlPanelModalLoop = true; | |||
const uint32 started = Time::getMillisecondCounter(); | |||
auto started = Time::getMillisecondCounter(); | |||
if (asioObject != nullptr) | |||
{ | |||
asioObject->controlPanel(); | |||
const int spent = (int) Time::getMillisecondCounter() - (int) started; | |||
auto spent = (int) (Time::getMillisecondCounter() - started); | |||
JUCE_ASIO_LOG ("spent: " + String (spent)); | |||
if (spent > 300) | |||
@@ -730,13 +704,10 @@ public: | |||
if (! insideControlPanelModalLoop) | |||
{ | |||
stopTimer(); | |||
JUCE_ASIO_LOG ("restart request!"); | |||
AudioIODeviceCallback* const oldCallback = currentCallback; | |||
auto* oldCallback = currentCallback; | |||
close(); | |||
needToReset = true; | |||
open (BigInteger (currentChansIn), BigInteger (currentChansOut), | |||
currentSampleRate, currentBlockSizeSamples); | |||
@@ -757,51 +728,49 @@ public: | |||
private: | |||
//============================================================================== | |||
WeakReference<ASIOAudioIODeviceType> owner; | |||
IASIO* volatile asioObject; | |||
IASIO* asioObject = {}; | |||
ASIOCallbacks callbacks; | |||
CLSID classId; | |||
String error; | |||
long totalNumInputChans, totalNumOutputChans; | |||
long totalNumInputChans = 0, totalNumOutputChans = 0; | |||
StringArray inputChannelNames, outputChannelNames; | |||
Array<double> sampleRates; | |||
Array<int> bufferSizes; | |||
long inputLatency, outputLatency; | |||
long minBufferSize, maxBufferSize, preferredBufferSize, bufferGranularity; | |||
ASIOClockSource clocks[32]; | |||
int numClockSources; | |||
int volatile currentBlockSizeSamples; | |||
int volatile currentBitDepth; | |||
double volatile currentSampleRate; | |||
long inputLatency = 0, outputLatency = 0; | |||
long minBufferSize = 0, maxBufferSize = 0, preferredBufferSize = 0, bufferGranularity = 0; | |||
ASIOClockSource clocks[32] = {}; | |||
int numClockSources = 0; | |||
int currentBlockSizeSamples = 0; | |||
int currentBitDepth = 16; | |||
double currentSampleRate = 0; | |||
BigInteger currentChansOut, currentChansIn; | |||
AudioIODeviceCallback* volatile currentCallback; | |||
AudioIODeviceCallback* currentCallback = {}; | |||
CriticalSection callbackLock; | |||
HeapBlock<ASIOBufferInfo> bufferInfos; | |||
HeapBlock<float*> inBuffers, outBuffers; | |||
HeapBlock<float> ioBufferSpace; | |||
HeapBlock<ASIOSampleFormat> inputFormat, outputFormat; | |||
int numActiveInputChans = 0, numActiveOutputChans = 0; | |||
WaitableEvent event1; | |||
HeapBlock<float> tempBuffer; | |||
int volatile bufferIndex, numActiveInputChans, numActiveOutputChans; | |||
bool deviceIsOpen, isStarted, buffersCreated; | |||
bool volatile calledback; | |||
bool volatile littleEndian, postOutput, needToReset; | |||
bool volatile insideControlPanelModalLoop; | |||
bool volatile shouldUsePreferredSize; | |||
bool deviceIsOpen = false, isStarted = false, buffersCreated = false; | |||
std::atomic<bool> calledback { false }; | |||
bool littleEndian = false, postOutput = true, needToReset = false; | |||
bool insideControlPanelModalLoop = false; | |||
bool shouldUsePreferredSize = false; | |||
int xruns = 0; | |||
//============================================================================== | |||
static String convertASIOString (char* const text, int length) | |||
static String convertASIOString (char* text, int length) | |||
{ | |||
if (CharPointer_UTF8::isValidString (text, length)) | |||
return String::fromUTF8 (text, length); | |||
WCHAR wideVersion [64] = { 0 }; | |||
WCHAR wideVersion[64] = {}; | |||
MultiByteToWideChar (CP_ACP, 0, text, length, wideVersion, numElementsInArray (wideVersion)); | |||
return wideVersion; | |||
} | |||
@@ -867,7 +836,7 @@ private: | |||
if (shouldUsePreferredSize) | |||
{ | |||
JUCE_ASIO_LOG ("Using preferred size for buffer.."); | |||
long err = refreshBufferSizes(); | |||
auto err = refreshBufferSizes(); | |||
if (err == ASE_OK) | |||
{ | |||
@@ -890,8 +859,8 @@ private: | |||
{ | |||
numActiveInputChans = 0; | |||
numActiveOutputChans = 0; | |||
auto* info = bufferInfos.get(); | |||
ASIOBufferInfo* info = bufferInfos; | |||
for (int i = 0; i < totalNumInputChans; ++i) | |||
{ | |||
if (inputChannels[i]) | |||
@@ -952,7 +921,7 @@ private: | |||
double getSampleRate() const | |||
{ | |||
double cr = 0; | |||
long err = asioObject->getSampleRate (&cr); | |||
auto err = asioObject->getSampleRate (&cr); | |||
JUCE_ASIO_LOG_ERROR ("getSampleRate", err); | |||
return cr; | |||
} | |||
@@ -962,7 +931,7 @@ private: | |||
if (currentSampleRate != newRate) | |||
{ | |||
JUCE_ASIO_LOG ("rate change: " + String (currentSampleRate) + " to " + String (newRate)); | |||
long err = asioObject->setSampleRate (newRate); | |||
auto err = asioObject->setSampleRate (newRate); | |||
if (err == ASE_NoClock && numClockSources > 0) | |||
{ | |||
@@ -970,7 +939,6 @@ private: | |||
Thread::sleep (10); | |||
err = asioObject->setClockSource (clocks[0].index); | |||
JUCE_ASIO_LOG_ERROR ("setClockSource2", err); | |||
Thread::sleep (10); | |||
err = asioObject->setSampleRate (newRate); | |||
} | |||
@@ -1009,7 +977,7 @@ private: | |||
if (numClockSources > 1 && ! isSourceSet) | |||
{ | |||
JUCE_ASIO_LOG ("setting clock source"); | |||
long err = asioObject->setClockSource (clocks[0].index); | |||
auto err = asioObject->setClockSource (clocks[0].index); | |||
JUCE_ASIO_LOG_ERROR ("setClockSource1", err); | |||
Thread::sleep (20); | |||
} | |||
@@ -1035,7 +1003,7 @@ private: | |||
numActiveInputChans = 0; | |||
numActiveOutputChans = 0; | |||
ASIOBufferInfo* info = bufferInfos; | |||
auto* info = bufferInfos.get(); | |||
int numChans = 0; | |||
for (int i = 0; i < jmin (2, (int) totalNumInputChans); ++i) | |||
@@ -1064,7 +1032,7 @@ private: | |||
if (preferredSize > 0) | |||
{ | |||
long err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks); | |||
auto err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks); | |||
JUCE_ASIO_LOG_ERROR ("dummy buffers", err); | |||
} | |||
@@ -1094,8 +1062,8 @@ private: | |||
if (i < 2) | |||
{ | |||
// clear the channels that are used with the dummy stuff | |||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[0], preferredBufferSize); | |||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[1], preferredBufferSize); | |||
outputFormat[i].clear (bufferInfos[outputBufferIndex + i].buffers[0], preferredBufferSize); | |||
outputFormat[i].clear (bufferInfos[outputBufferIndex + i].buffers[1], preferredBufferSize); | |||
} | |||
} | |||
} | |||
@@ -1140,7 +1108,7 @@ private: | |||
String getLastDriverError() const | |||
{ | |||
jassert (asioObject != nullptr); | |||
char buffer [512] = { 0 }; | |||
char buffer[512] = {}; | |||
asioObject->getErrorMessage (buffer); | |||
return String (buffer, sizeof (buffer) - 1); | |||
} | |||
@@ -1163,7 +1131,7 @@ private: | |||
if (driverError.isEmpty()) | |||
{ | |||
char buffer [512]; | |||
char buffer[512] = {}; | |||
asioObject->getDriverName (buffer); // just in case any flimsy drivers expect this to be called.. | |||
} | |||
@@ -1187,7 +1155,6 @@ private: | |||
numActiveOutputChans = 0; | |||
xruns = 0; | |||
currentCallback = nullptr; | |||
error.clear(); | |||
if (getName().isEmpty()) | |||
@@ -1220,7 +1187,7 @@ private: | |||
{ | |||
addBufferSizes (minBufferSize, maxBufferSize, preferredBufferSize, bufferGranularity); | |||
double currentRate = getSampleRate(); | |||
auto currentRate = getSampleRate(); | |||
if (currentRate < 1.0 || currentRate > 192001.0) | |||
{ | |||
@@ -1232,13 +1199,12 @@ private: | |||
} | |||
currentSampleRate = currentRate; | |||
postOutput = (asioObject->outputReady() == 0); | |||
if (postOutput) | |||
JUCE_ASIO_LOG ("outputReady true"); | |||
updateSampleRates(); | |||
readLatencies(); // ..doing these steps because cubase does so at this stage | |||
createDummyBuffers (preferredBufferSize); // in initialisation, and some devices fail if we don't. | |||
readLatencies(); | |||
@@ -1294,12 +1260,11 @@ private: | |||
} | |||
//============================================================================== | |||
void JUCE_ASIOCALLBACK callback (const long index) | |||
void JUCE_ASIOCALLBACK callback (long index) | |||
{ | |||
if (isStarted) | |||
{ | |||
bufferIndex = index; | |||
processBuffer(); | |||
processBuffer (index); | |||
} | |||
else | |||
{ | |||
@@ -1310,23 +1275,21 @@ private: | |||
calledback = true; | |||
} | |||
void processBuffer() | |||
void processBuffer (long bufferIndex) | |||
{ | |||
const ASIOBufferInfo* const infos = bufferInfos; | |||
const int bi = bufferIndex; | |||
const ScopedLock sl (callbackLock); | |||
if (bi >= 0) | |||
if (bufferIndex >= 0) | |||
{ | |||
const int samps = currentBlockSizeSamples; | |||
auto* infos = bufferInfos.get(); | |||
auto samps = currentBlockSizeSamples; | |||
if (currentCallback != nullptr) | |||
{ | |||
for (int i = 0; i < numActiveInputChans; ++i) | |||
{ | |||
jassert (inBuffers[i] != nullptr); | |||
inputFormat[i].convertToFloat (infos[i].buffers[bi], inBuffers[i], samps); | |||
inputFormat[i].convertToFloat (infos[i].buffers[bufferIndex], inBuffers[i], samps); | |||
} | |||
currentCallback->audioDeviceIOCallback (const_cast<const float**> (inBuffers.getData()), numActiveInputChans, | |||
@@ -1335,13 +1298,13 @@ private: | |||
for (int i = 0; i < numActiveOutputChans; ++i) | |||
{ | |||
jassert (outBuffers[i] != nullptr); | |||
outputFormat[i].convertFromFloat (outBuffers[i], infos [numActiveInputChans + i].buffers[bi], samps); | |||
outputFormat[i].convertFromFloat (outBuffers[i], infos[numActiveInputChans + i].buffers[bufferIndex], samps); | |||
} | |||
} | |||
else | |||
{ | |||
for (int i = 0; i < numActiveOutputChans; ++i) | |||
outputFormat[i].clear (infos[numActiveInputChans + i].buffers[bi], samps); | |||
outputFormat[i].clear (infos[numActiveInputChans + i].buffers[bufferIndex], samps); | |||
} | |||
} | |||
@@ -1359,15 +1322,15 @@ private: | |||
return 1; | |||
break; | |||
case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); resetRequest(); return 1; | |||
case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); resetRequest(); return 1; | |||
case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); resetRequest(); return 1; | |||
case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1; | |||
case kAsioEngineVersion: return 2; | |||
case kAsioBufferSizeChange: JUCE_ASIO_LOG ("kAsioBufferSizeChange"); resetRequest(); return 1; | |||
case kAsioResetRequest: JUCE_ASIO_LOG ("kAsioResetRequest"); resetRequest(); return 1; | |||
case kAsioResyncRequest: JUCE_ASIO_LOG ("kAsioResyncRequest"); resetRequest(); return 1; | |||
case kAsioLatenciesChanged: JUCE_ASIO_LOG ("kAsioLatenciesChanged"); return 1; | |||
case kAsioEngineVersion: return 2; | |||
case kAsioSupportsTimeInfo: | |||
case kAsioSupportsTimeCode: return 0; | |||
case kAsioOverload: xruns++; return 1; | |||
case kAsioOverload: ++xruns; return 1; | |||
} | |||
return 0; | |||
@@ -1379,29 +1342,30 @@ private: | |||
{ | |||
static ASIOTime* JUCE_ASIOCALLBACK bufferSwitchTimeInfoCallback (ASIOTime*, long index, long) | |||
{ | |||
if (currentASIODev[deviceIndex] != nullptr) | |||
currentASIODev[deviceIndex]->callback (index); | |||
if (auto* d = currentASIODev[deviceIndex]) | |||
d->callback (index); | |||
return nullptr; | |||
return {}; | |||
} | |||
static void JUCE_ASIOCALLBACK bufferSwitchCallback (long index, long) | |||
{ | |||
if (currentASIODev[deviceIndex] != nullptr) | |||
currentASIODev[deviceIndex]->callback (index); | |||
if (auto* d = currentASIODev[deviceIndex]) | |||
d->callback (index); | |||
} | |||
static long JUCE_ASIOCALLBACK asioMessagesCallback (long selector, long value, void*, double*) | |||
{ | |||
return currentASIODev[deviceIndex] != nullptr | |||
? currentASIODev[deviceIndex]->asioMessagesCallback (selector, value) | |||
: 0; | |||
if (auto* d = currentASIODev[deviceIndex]) | |||
return d->asioMessagesCallback (selector, value); | |||
return {}; | |||
} | |||
static void JUCE_ASIOCALLBACK sampleRateChangedCallback (ASIOSampleRate) | |||
{ | |||
if (currentASIODev[deviceIndex] != nullptr) | |||
currentASIODev[deviceIndex]->resetRequest(); | |||
if (auto* d = currentASIODev[deviceIndex]) | |||
d->resetRequest(); | |||
} | |||
static void setCallbacks (ASIOCallbacks& callbacks) noexcept | |||
@@ -1430,7 +1394,7 @@ private: | |||
}; | |||
template <> | |||
struct ASIOAudioIODevice::ASIOCallbackFunctions <sizeof(currentASIODev) / sizeof(currentASIODev[0])> | |||
struct ASIOAudioIODevice::ASIOCallbackFunctions<maxNumASIODevices> | |||
{ | |||
static void setCallbacksForDevice (ASIOCallbacks&, ASIOAudioIODevice*) noexcept {} | |||
}; | |||
@@ -1442,10 +1406,9 @@ public: | |||
ASIOAudioIODeviceType() : AudioIODeviceType ("ASIO") {} | |||
//============================================================================== | |||
void scanForDevices() | |||
void scanForDevices() override | |||
{ | |||
hasScanned = true; | |||
deviceNames.clear(); | |||
classIds.clear(); | |||
@@ -1454,7 +1417,7 @@ public: | |||
if (RegOpenKey (HKEY_LOCAL_MACHINE, _T("software\\asio"), &hk) == ERROR_SUCCESS) | |||
{ | |||
TCHAR name [256]; | |||
TCHAR name[256] = {}; | |||
while (RegEnumKey (hk, index++, name, numElementsInArray (name)) == ERROR_SUCCESS) | |||
addDriverInfo (name, hk); | |||
@@ -1463,14 +1426,13 @@ public: | |||
} | |||
} | |||
StringArray getDeviceNames (bool /*wantInputNames*/) const | |||
StringArray getDeviceNames (bool /*wantInputNames*/) const override | |||
{ | |||
jassert (hasScanned); // need to call scanForDevices() before doing this | |||
return deviceNames; | |||
} | |||
int getDefaultDeviceIndex (bool) const | |||
int getDefaultDeviceIndex (bool) const override | |||
{ | |||
jassert (hasScanned); // need to call scanForDevices() before doing this | |||
@@ -1489,8 +1451,8 @@ public: | |||
static int findFreeSlot() | |||
{ | |||
for (int i = 0; i < numElementsInArray (currentASIODev); ++i) | |||
if (currentASIODev[i] == 0) | |||
for (int i = 0; i < maxNumASIODevices; ++i) | |||
if (currentASIODev[i] == nullptr) | |||
return i; | |||
jassertfalse; // unfortunately you can only have a finite number | |||
@@ -1498,29 +1460,29 @@ public: | |||
return -1; | |||
} | |||
int getIndexOfDevice (AudioIODevice* d, bool /*asInput*/) const | |||
int getIndexOfDevice (AudioIODevice* d, bool /*asInput*/) const override | |||
{ | |||
jassert (hasScanned); // need to call scanForDevices() before doing this | |||
return d == nullptr ? -1 : deviceNames.indexOf (d->getName()); | |||
} | |||
bool hasSeparateInputsAndOutputs() const { return false; } | |||
bool hasSeparateInputsAndOutputs() const override { return false; } | |||
AudioIODevice* createDevice (const String& outputDeviceName, | |||
const String& inputDeviceName) | |||
const String& inputDeviceName) override | |||
{ | |||
// ASIO can't open two different devices for input and output - they must be the same one. | |||
jassert (inputDeviceName == outputDeviceName || outputDeviceName.isEmpty() || inputDeviceName.isEmpty()); | |||
jassert (hasScanned); // need to call scanForDevices() before doing this | |||
const String deviceName (outputDeviceName.isNotEmpty() ? outputDeviceName | |||
: inputDeviceName); | |||
const int index = deviceNames.indexOf (deviceName); | |||
auto deviceName = outputDeviceName.isNotEmpty() ? outputDeviceName | |||
: inputDeviceName; | |||
auto index = deviceNames.indexOf (deviceName); | |||
if (index >= 0) | |||
{ | |||
const int freeSlot = findFreeSlot(); | |||
auto freeSlot = findFreeSlot(); | |||
if (freeSlot >= 0) | |||
return new ASIOAudioIODevice (this, deviceName, | |||
@@ -1552,7 +1514,7 @@ private: | |||
if (RegOpenKey (HKEY_CLASSES_ROOT, _T("clsid"), &hk) == ERROR_SUCCESS) | |||
{ | |||
int index = 0; | |||
TCHAR name [512]; | |||
TCHAR name[512] = {}; | |||
while (RegEnumKey (hk, index++, name, numElementsInArray (name)) == ERROR_SUCCESS) | |||
{ | |||
@@ -1564,7 +1526,7 @@ private: | |||
{ | |||
if (RegOpenKeyEx (subKey, _T("InprocServer32"), 0, KEY_READ, &pathKey) == ERROR_SUCCESS) | |||
{ | |||
TCHAR pathName [1024] = { 0 }; | |||
TCHAR pathName[1024] = {}; | |||
DWORD dtype = REG_SZ; | |||
DWORD dsize = sizeof (pathName); | |||
@@ -1596,7 +1558,7 @@ private: | |||
if (RegOpenKeyEx (hk, keyName.toWideCharPointer(), 0, KEY_READ, &subKey) == ERROR_SUCCESS) | |||
{ | |||
TCHAR buf [256] = { 0 }; | |||
TCHAR buf[256] = {}; | |||
DWORD dtype = REG_SZ; | |||
DWORD dsize = sizeof (buf); | |||
@@ -1605,6 +1567,7 @@ private: | |||
if (dsize > 0 && checkClassIsOk (buf)) | |||
{ | |||
CLSID classId; | |||
if (CLSIDFromString ((LPOLESTR) buf, &classId) == S_OK) | |||
{ | |||
dtype = REG_SZ; | |||
@@ -192,7 +192,7 @@ JUCE_IUNKNOWNCLASS (IMMDeviceEnumerator, "A95664D2-9614-4F35-A746-DE8DB63617E6") | |||
JUCE_COMCLASS (MMDeviceEnumerator, "BCDE0395-E52F-467C-8E3D-C4579291692E"); | |||
typedef LONGLONG REFERENCE_TIME; | |||
using REFERENCE_TIME = LONGLONG; | |||
enum AVRT_PRIORITY | |||
{ | |||
@@ -308,7 +308,7 @@ JUCE_IUNKNOWNCLASS (IAudioSessionControl, "F4B1A599-7266-4319-A8CA-E70ACB11E8CD" | |||
namespace WasapiClasses | |||
{ | |||
String getDeviceID (IMMDevice* const device) | |||
String getDeviceID (IMMDevice* device) | |||
{ | |||
String s; | |||
WCHAR* deviceId = nullptr; | |||
@@ -332,17 +332,17 @@ EDataFlow getDataFlow (const ComSmartPtr<IMMDevice>& device) | |||
return flow; | |||
} | |||
int refTimeToSamples (const REFERENCE_TIME& t, const double sampleRate) noexcept | |||
int refTimeToSamples (const REFERENCE_TIME& t, double sampleRate) noexcept | |||
{ | |||
return roundToInt (sampleRate * ((double) t) * 0.0000001); | |||
} | |||
REFERENCE_TIME samplesToRefTime (const int numSamples, const double sampleRate) noexcept | |||
REFERENCE_TIME samplesToRefTime (int numSamples, double sampleRate) noexcept | |||
{ | |||
return (REFERENCE_TIME) ((numSamples * 10000.0 * 1000.0 / sampleRate) + 0.5); | |||
} | |||
void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) noexcept | |||
void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* src) noexcept | |||
{ | |||
memcpy (&dest, src, src->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? sizeof (WAVEFORMATEXTENSIBLE) | |||
: sizeof (WAVEFORMATEX)); | |||
@@ -352,21 +352,8 @@ void copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX* const src) n | |||
class WASAPIDeviceBase | |||
{ | |||
public: | |||
WASAPIDeviceBase (const ComSmartPtr<IMMDevice>& d, const bool exclusiveMode) | |||
: device (d), | |||
sampleRate (0), | |||
defaultSampleRate (0), | |||
numChannels (0), | |||
actualNumChannels (0), | |||
minBufferSize (0), | |||
defaultBufferSize (0), | |||
latencySamples (0), | |||
useExclusiveMode (exclusiveMode), | |||
actualBufferSize (0), | |||
bytesPerSample (0), | |||
bytesPerFrame (0), | |||
sampleRateHasChanged (false), | |||
shouldClose (false) | |||
WASAPIDeviceBase (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode) | |||
: device (d), useExclusiveMode (exclusiveMode) | |||
{ | |||
clientEvent = CreateEvent (nullptr, false, false, nullptr); | |||
@@ -443,20 +430,19 @@ public: | |||
{ | |||
sampleRateHasChanged = false; | |||
shouldClose = false; | |||
channelMaps.clear(); | |||
for (int i = 0; i <= channels.getHighestBit(); ++i) | |||
if (channels[i]) | |||
channelMaps.add (i); | |||
REFERENCE_TIME latency; | |||
if (check (client->GetStreamLatency (&latency))) | |||
latencySamples = refTimeToSamples (latency, sampleRate); | |||
(void) check (client->GetBufferSize (&actualBufferSize)); | |||
createSessionEventCallback(); | |||
return check (client->SetEventHandle (clientEvent)); | |||
} | |||
@@ -486,26 +472,25 @@ public: | |||
//============================================================================== | |||
ComSmartPtr<IMMDevice> device; | |||
ComSmartPtr<IAudioClient> client; | |||
double sampleRate, defaultSampleRate; | |||
int numChannels, actualNumChannels; | |||
int minBufferSize, defaultBufferSize, latencySamples; | |||
DWORD mixFormatChannelMask; | |||
double sampleRate = 0, defaultSampleRate = 0; | |||
int numChannels = 0, actualNumChannels = 0; | |||
int minBufferSize = 0, defaultBufferSize = 0, latencySamples = 0; | |||
DWORD mixFormatChannelMask = 0; | |||
const bool useExclusiveMode; | |||
Array<double> rates; | |||
HANDLE clientEvent; | |||
HANDLE clientEvent = {}; | |||
BigInteger channels; | |||
Array<int> channelMaps; | |||
UINT32 actualBufferSize; | |||
int bytesPerSample, bytesPerFrame; | |||
bool sampleRateHasChanged, shouldClose; | |||
UINT32 actualBufferSize = 0; | |||
int bytesPerSample = 0, bytesPerFrame = 0; | |||
bool sampleRateHasChanged = false, shouldClose = false; | |||
virtual void updateFormat (bool isFloat) = 0; | |||
private: | |||
//============================================================================== | |||
class SessionEventCallback : public ComBaseClassHelper<IAudioSessionEvents> | |||
struct SessionEventCallback : public ComBaseClassHelper<IAudioSessionEvents> | |||
{ | |||
public: | |||
SessionEventCallback (WASAPIDeviceBase& d) : owner (d) {} | |||
JUCE_COMRESULT OnDisplayNameChanged (LPCWSTR, LPCGUID) { return S_OK; } | |||
@@ -513,6 +498,7 @@ private: | |||
JUCE_COMRESULT OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; } | |||
JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } | |||
JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } | |||
JUCE_COMRESULT OnStateChanged(AudioSessionState state) | |||
{ | |||
if (state == AudioSessionStateInactive || state == AudioSessionStateExpired) | |||
@@ -530,9 +516,7 @@ private: | |||
return S_OK; | |||
} | |||
private: | |||
WASAPIDeviceBase& owner; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SessionEventCallback) | |||
}; | |||
@@ -644,7 +628,7 @@ private: | |||
return false; | |||
} | |||
bool tryInitialisingWithBufferSize (const int bufferSizeSamples) | |||
bool tryInitialisingWithBufferSize (int bufferSizeSamples) | |||
{ | |||
WAVEFORMATEXTENSIBLE format; | |||
@@ -701,9 +685,8 @@ private: | |||
class WASAPIInputDevice : public WASAPIDeviceBase | |||
{ | |||
public: | |||
WASAPIInputDevice (const ComSmartPtr<IMMDevice>& d, const bool exclusiveMode) | |||
: WASAPIDeviceBase (d, exclusiveMode), | |||
reservoir (1, 1) | |||
WASAPIInputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode) | |||
: WASAPIDeviceBase (d, exclusiveMode) | |||
{ | |||
} | |||
@@ -712,7 +695,7 @@ public: | |||
close(); | |||
} | |||
bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
bool open (double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
{ | |||
return openClient (newSampleRate, newChannels, bufferSizeSamples) | |||
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), | |||
@@ -724,13 +707,14 @@ public: | |||
closeClient(); | |||
captureClient = nullptr; | |||
reservoir.reset(); | |||
reservoirReadPos = reservoirWritePos = 0; | |||
reservoirReadPos = 0; | |||
reservoirWritePos = 0; | |||
} | |||
template<class SourceType> | |||
void updateFormatWithType (SourceType*) noexcept | |||
{ | |||
typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> NativeType; | |||
using NativeType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>; | |||
converter.reset (new AudioData::ConverterInstance<AudioData::Pointer<SourceType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, NativeType> (actualNumChannels, 1)); | |||
} | |||
@@ -742,12 +726,13 @@ public: | |||
else updateFormatWithType ((AudioData::Int16*) nullptr); | |||
} | |||
bool start (const int userBufferSize) | |||
bool start (int userBufferSize) | |||
{ | |||
reservoirSize = actualBufferSize + userBufferSize; | |||
reservoirMask = nextPowerOfTwo (reservoirSize) - 1; | |||
reservoir.setSize ((reservoirMask + 1) * bytesPerFrame, true); | |||
reservoirReadPos = reservoirWritePos = 0; | |||
reservoirReadPos = 0; | |||
reservoirWritePos = 0; | |||
xruns = 0; | |||
if (! check (client->Start())) | |||
@@ -768,7 +753,7 @@ public: | |||
captureClient->ReleaseBuffer (numSamplesAvailable); | |||
} | |||
int getNumSamplesInReservoir() const noexcept { return reservoirWritePos - reservoirReadPos; } | |||
int getNumSamplesInReservoir() const noexcept { return reservoirWritePos.load() - reservoirReadPos.load(); } | |||
void handleDeviceBuffer() | |||
{ | |||
@@ -788,9 +773,9 @@ public: | |||
while (samplesLeft > 0) | |||
{ | |||
const int localWrite = reservoirWritePos & reservoirMask; | |||
const int samplesToDo = jmin (samplesLeft, reservoirMask + 1 - localWrite); | |||
const int samplesToDoBytes = samplesToDo * bytesPerFrame; | |||
auto localWrite = reservoirWritePos.load() & reservoirMask; | |||
auto samplesToDo = jmin (samplesLeft, reservoirMask + 1 - localWrite); | |||
auto samplesToDoBytes = samplesToDo * bytesPerFrame; | |||
void* reservoirPtr = addBytesToPointer (reservoir.getData(), localWrite * bytesPerFrame); | |||
@@ -805,7 +790,7 @@ public: | |||
} | |||
if (getNumSamplesInReservoir() > reservoirSize) | |||
reservoirReadPos = reservoirWritePos - reservoirSize; | |||
reservoirReadPos = reservoirWritePos.load() - reservoirSize; | |||
captureClient->ReleaseBuffer (numSamplesAvailable); | |||
} | |||
@@ -829,13 +814,13 @@ public: | |||
while (bufferSize > 0) | |||
{ | |||
const int localRead = reservoirReadPos & reservoirMask; | |||
auto localRead = reservoirReadPos.load() & reservoirMask; | |||
auto samplesToDo = jmin (bufferSize, getNumSamplesInReservoir(), reservoirMask + 1 - localRead); | |||
const int samplesToDo = jmin (bufferSize, getNumSamplesInReservoir(), reservoirMask + 1 - localRead); | |||
if (samplesToDo <= 0) | |||
break; | |||
const int reservoirOffset = localRead * bytesPerFrame; | |||
auto reservoirOffset = localRead * bytesPerFrame; | |||
for (int i = 0; i < numDestBuffers; ++i) | |||
converter->convertSamples (destBuffers[i] + offset, 0, addBytesToPointer (reservoir.getData(), reservoirOffset), channelMaps.getUnchecked(i), samplesToDo); | |||
@@ -849,7 +834,7 @@ public: | |||
ComSmartPtr<IAudioCaptureClient> captureClient; | |||
MemoryBlock reservoir; | |||
int reservoirSize, reservoirMask, xruns; | |||
volatile int reservoirReadPos, reservoirWritePos; | |||
std::atomic<int> reservoirReadPos, reservoirWritePos; | |||
std::unique_ptr<AudioData::Converter> converter; | |||
@@ -861,7 +846,7 @@ private: | |||
class WASAPIOutputDevice : public WASAPIDeviceBase | |||
{ | |||
public: | |||
WASAPIOutputDevice (const ComSmartPtr<IMMDevice>& d, const bool exclusiveMode) | |||
WASAPIOutputDevice (const ComSmartPtr<IMMDevice>& d, bool exclusiveMode) | |||
: WASAPIDeviceBase (d, exclusiveMode) | |||
{ | |||
} | |||
@@ -871,7 +856,7 @@ public: | |||
close(); | |||
} | |||
bool open (const double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
bool open (double newSampleRate, const BigInteger& newChannels, int bufferSizeSamples) | |||
{ | |||
return openClient (newSampleRate, newChannels, bufferSizeSamples) | |||
&& (numChannels == 0 || check (client->GetService (__uuidof (IAudioRenderClient), | |||
@@ -887,7 +872,7 @@ public: | |||
template<class DestType> | |||
void updateFormatWithType (DestType*) | |||
{ | |||
typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> NativeType; | |||
using NativeType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>; | |||
converter.reset (new AudioData::ConverterInstance<NativeType, AudioData::Pointer<DestType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst>> (1, actualNumChannels)); | |||
} | |||
@@ -901,7 +886,7 @@ public: | |||
bool start() | |||
{ | |||
int samplesToDo = getNumSamplesAvailableToCopy(); | |||
auto samplesToDo = getNumSamplesAvailableToCopy(); | |||
uint8* outputData; | |||
if (check (renderClient->GetBuffer (samplesToDo, &outputData))) | |||
@@ -918,6 +903,7 @@ public: | |||
if (! useExclusiveMode) | |||
{ | |||
UINT32 padding = 0; | |||
if (check (client->GetCurrentPadding (&padding))) | |||
return actualBufferSize - (int) padding; | |||
} | |||
@@ -925,7 +911,7 @@ public: | |||
return actualBufferSize; | |||
} | |||
void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, | |||
void copyBuffers (const float** srcBuffers, int numSrcBuffers, int bufferSize, | |||
WASAPIInputDevice* inputDevice, Thread& thread) | |||
{ | |||
if (numChannels <= 0) | |||
@@ -985,18 +971,12 @@ public: | |||
const String& typeName, | |||
const String& outputDeviceID, | |||
const String& inputDeviceID, | |||
const bool exclusiveMode) | |||
bool exclusiveMode) | |||
: AudioIODevice (deviceName, typeName), | |||
Thread ("JUCE WASAPI"), | |||
outputDeviceId (outputDeviceID), | |||
inputDeviceId (inputDeviceID), | |||
useExclusiveMode (exclusiveMode), | |||
isOpen_ (false), | |||
isStarted (false), | |||
currentBufferSizeSamples (0), | |||
currentSampleRate (0), | |||
callback (nullptr), | |||
deviceBecameInactive (false) | |||
useExclusiveMode (exclusiveMode) | |||
{ | |||
} | |||
@@ -1085,7 +1065,7 @@ public: | |||
BigInteger getActiveOutputChannels() const override { return outputDevice != nullptr ? outputDevice->channels : BigInteger(); } | |||
BigInteger getActiveInputChannels() const override { return inputDevice != nullptr ? inputDevice->channels : BigInteger(); } | |||
String getLastError() override { return lastError; } | |||
int getXRunCount () const noexcept override { return inputDevice != nullptr ? inputDevice->xruns : -1; } | |||
int getXRunCount() const noexcept override { return inputDevice != nullptr ? inputDevice->xruns : -1; } | |||
String open (const BigInteger& inputChannels, const BigInteger& outputChannels, | |||
double sampleRate, int bufferSizeSamples) override | |||
@@ -1209,7 +1189,7 @@ public: | |||
{ | |||
if (isStarted) | |||
{ | |||
AudioIODeviceCallback* const callbackLocal = callback; | |||
auto* callbackLocal = callback; | |||
{ | |||
const ScopedLock sl (startStopLock); | |||
@@ -1230,9 +1210,8 @@ public: | |||
if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0) | |||
{ | |||
DWORD dummy = 0; | |||
HANDLE h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy); | |||
if (h != 0) | |||
if (auto h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy)) | |||
avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL); | |||
} | |||
} | |||
@@ -1241,15 +1220,15 @@ public: | |||
{ | |||
setMMThreadPriority(); | |||
const int bufferSize = currentBufferSizeSamples; | |||
const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); | |||
const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); | |||
auto bufferSize = currentBufferSizeSamples; | |||
auto numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); | |||
auto numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); | |||
bool sampleRateHasChanged = false; | |||
AudioBuffer<float> ins (jmax (1, numInputBuffers), bufferSize + 32); | |||
AudioBuffer<float> outs (jmax (1, numOutputBuffers), bufferSize + 32); | |||
float** const inputBuffers = ins.getArrayOfWritePointers(); | |||
float** const outputBuffers = outs.getArrayOfWritePointers(); | |||
auto inputBuffers = ins.getArrayOfWritePointers(); | |||
auto outputBuffers = outs.getArrayOfWritePointers(); | |||
ins.clear(); | |||
outs.clear(); | |||
@@ -1329,21 +1308,21 @@ private: | |||
std::unique_ptr<WASAPIInputDevice> inputDevice; | |||
std::unique_ptr<WASAPIOutputDevice> outputDevice; | |||
const bool useExclusiveMode; | |||
double defaultSampleRate; | |||
int minBufferSize, defaultBufferSize; | |||
int latencyIn, latencyOut; | |||
double defaultSampleRate = 0; | |||
int minBufferSize = 0, defaultBufferSize = 0; | |||
int latencyIn = 0, latencyOut = 0; | |||
Array<double> sampleRates; | |||
Array<int> bufferSizes; | |||
// Active state... | |||
bool isOpen_, isStarted; | |||
int currentBufferSizeSamples; | |||
double currentSampleRate; | |||
bool isOpen_ = false, isStarted = false; | |||
int currentBufferSizeSamples = 0; | |||
double currentSampleRate = 0; | |||
AudioIODeviceCallback* callback; | |||
AudioIODeviceCallback* callback = {}; | |||
CriticalSection startStopLock; | |||
bool sampleRateChangedByOutput, deviceBecameInactive; | |||
bool sampleRateChangedByOutput = false, deviceBecameInactive = false; | |||
BigInteger lastKnownInputChannels, lastKnownOutputChannels; | |||
@@ -1351,28 +1330,33 @@ private: | |||
bool createDevices() | |||
{ | |||
ComSmartPtr<IMMDeviceEnumerator> enumerator; | |||
if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) | |||
return false; | |||
ComSmartPtr<IMMDeviceCollection> deviceCollection; | |||
if (! check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, deviceCollection.resetAndGetPointerAddress()))) | |||
return false; | |||
UINT32 numDevices = 0; | |||
if (! check (deviceCollection->GetCount (&numDevices))) | |||
return false; | |||
for (UINT32 i = 0; i < numDevices; ++i) | |||
{ | |||
ComSmartPtr<IMMDevice> device; | |||
if (! check (deviceCollection->Item (i, device.resetAndGetPointerAddress()))) | |||
continue; | |||
const String deviceId (getDeviceID (device)); | |||
auto deviceId = getDeviceID (device); | |||
if (deviceId.isEmpty()) | |||
continue; | |||
const EDataFlow flow = getDataFlow (device); | |||
auto flow = getDataFlow (device); | |||
if (deviceId == inputDeviceId && flow == eCapture) | |||
inputDevice.reset (new WASAPIInputDevice (device, useExclusiveMode)); | |||
@@ -1381,7 +1365,7 @@ private: | |||
} | |||
return (outputDeviceId.isEmpty() || (outputDevice != nullptr && outputDevice->isOk())) | |||
&& (inputDeviceId.isEmpty() || (inputDevice != nullptr && inputDevice->isOk())); | |||
&& (inputDeviceId.isEmpty() || (inputDevice != nullptr && inputDevice->isOk())); | |||
} | |||
//============================================================================== | |||
@@ -1428,8 +1412,7 @@ public: | |||
WASAPIAudioIODeviceType (bool exclusive) | |||
: AudioIODeviceType (exclusive ? "Windows Audio (Exclusive Mode)" : "Windows Audio"), | |||
DeviceChangeDetector (L"Windows Audio"), | |||
exclusiveMode (exclusive), | |||
hasScanned (false) | |||
exclusiveMode (exclusive) | |||
{ | |||
} | |||
@@ -1471,7 +1454,7 @@ public: | |||
{ | |||
jassert (hasScanned); // need to call scanForDevices() before doing this | |||
if (WASAPIAudioIODevice* const d = dynamic_cast<WASAPIAudioIODevice*> (device)) | |||
if (auto d = dynamic_cast<WASAPIAudioIODevice*> (device)) | |||
return asInput ? inputDeviceIds.indexOf (d->inputDeviceId) | |||
: outputDeviceIds.indexOf (d->outputDeviceId); | |||
@@ -1487,8 +1470,8 @@ public: | |||
std::unique_ptr<WASAPIAudioIODevice> device; | |||
const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); | |||
const int inputIndex = inputDeviceNames.indexOf (inputDeviceName); | |||
auto outputIndex = outputDeviceNames.indexOf (outputDeviceName); | |||
auto inputIndex = inputDeviceNames.indexOf (inputDeviceName); | |||
if (outputIndex >= 0 || inputIndex >= 0) | |||
{ | |||
@@ -1511,7 +1494,8 @@ public: | |||
StringArray inputDeviceNames, inputDeviceIds; | |||
private: | |||
bool exclusiveMode, hasScanned; | |||
const bool exclusiveMode; | |||
bool hasScanned = false; | |||
ComSmartPtr<IMMDeviceEnumerator> enumerator; | |||
//============================================================================== | |||
@@ -1538,7 +1522,7 @@ private: | |||
ComSmartPtr<ChangeNotificationClient> notifyClient; | |||
//============================================================================== | |||
static String getDefaultEndpoint (IMMDeviceEnumerator* const enumerator, const bool forCapture) | |||
static String getDefaultEndpoint (IMMDeviceEnumerator* enumerator, bool forCapture) | |||
{ | |||
String s; | |||
IMMDevice* dev = nullptr; | |||
@@ -1575,8 +1559,8 @@ private: | |||
enumerator->RegisterEndpointNotificationCallback (notifyClient); | |||
} | |||
const String defaultRenderer (getDefaultEndpoint (enumerator, false)); | |||
const String defaultCapture (getDefaultEndpoint (enumerator, true)); | |||
auto defaultRenderer = getDefaultEndpoint (enumerator, false); | |||
auto defaultCapture = getDefaultEndpoint (enumerator, true); | |||
ComSmartPtr<IMMDeviceCollection> deviceCollection; | |||
UINT32 numDevices = 0; | |||
@@ -1588,18 +1572,21 @@ private: | |||
for (UINT32 i = 0; i < numDevices; ++i) | |||
{ | |||
ComSmartPtr<IMMDevice> device; | |||
if (! check (deviceCollection->Item (i, device.resetAndGetPointerAddress()))) | |||
continue; | |||
DWORD state = 0; | |||
if (! (check (device->GetState (&state)) && state == DEVICE_STATE_ACTIVE)) | |||
continue; | |||
const String deviceId (getDeviceID (device)); | |||
auto deviceId = getDeviceID (device); | |||
String name; | |||
{ | |||
ComSmartPtr<IPropertyStore> properties; | |||
if (! check (device->OpenPropertyStore (STGM_READ, properties.resetAndGetPointerAddress()))) | |||
continue; | |||
@@ -1615,7 +1602,7 @@ private: | |||
PropVariantClear (&value); | |||
} | |||
const EDataFlow flow = getDataFlow (device); | |||
auto flow = getDataFlow (device); | |||
if (flow == eRender) | |||
{ | |||
@@ -1666,9 +1653,11 @@ struct MMDeviceMasterVolume | |||
MMDeviceMasterVolume() | |||
{ | |||
ComSmartPtr<IMMDeviceEnumerator> enumerator; | |||
if (check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) | |||
{ | |||
ComSmartPtr<IMMDevice> device; | |||
if (check (enumerator->GetDefaultAudioEndpoint (eRender, eConsole, device.resetAndGetPointerAddress()))) | |||
check (device->Activate (__uuidof (IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, | |||
(void**) endpointVolume.resetAndGetPointerAddress())); | |||
@@ -1678,6 +1667,7 @@ struct MMDeviceMasterVolume | |||
float getGain() const | |||
{ | |||
float vol = 0.0f; | |||
if (endpointVolume != nullptr) | |||
check (endpointVolume->GetMasterVolumeLevelScalar (&vol)); | |||
@@ -166,11 +166,11 @@ private: | |||
AudioSource* masterSource = nullptr; | |||
CriticalSection callbackLock; | |||
float volatile gain = 1.0f, lastGain = 1.0f; | |||
bool volatile playing = false, stopped = true; | |||
float gain = 1.0f, lastGain = 1.0f; | |||
bool playing = false, stopped = true; | |||
double sampleRate = 44100.0, sourceSampleRate = 0; | |||
int blockSize = 128, readAheadBufferSize = 0; | |||
bool volatile isPrepared = false, inputStreamEOF = false; | |||
bool isPrepared = false, inputStreamEOF = false; | |||
void releaseMasterResources(); | |||
@@ -93,8 +93,8 @@ private: | |||
//============================================================================== | |||
OptionalScopedPointer<AudioFormatReader> reader; | |||
int64 volatile nextPlayPos; | |||
bool volatile looping; | |||
int64 nextPlayPos; | |||
bool looping; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioFormatReaderSource) | |||
}; | |||
@@ -170,7 +170,7 @@ bool AudioFormatWriter::writeFromFloatArrays (const float* const* channels, int | |||
while (numSamples > 0) | |||
{ | |||
const int numToDo = jmin (numSamples, maxSamples); | |||
auto numToDo = jmin (numSamples, maxSamples); | |||
for (int i = 0; i < numSourceChannels; ++i) | |||
convertFloatsToInts (chans[i], channels[i] + startSample, numToDo); | |||
@@ -217,12 +217,7 @@ public: | |||
: fifo (numSamples), | |||
buffer (channels, numSamples), | |||
timeSliceThread (tst), | |||
writer (w), | |||
receiver (nullptr), | |||
samplesWritten (0), | |||
samplesPerFlush (0), | |||
flushSampleCounter (0), | |||
isRunning (true) | |||
writer (w) | |||
{ | |||
timeSliceThread.addTimeSliceClient (this); | |||
} | |||
@@ -267,7 +262,7 @@ public: | |||
int writePendingData() | |||
{ | |||
const int numToDo = fifo.getTotalSize() / 4; | |||
auto numToDo = fifo.getTotalSize() / 4; | |||
int start1, size1, start2, size2; | |||
fifo.prepareToRead (numToDo, start1, size1, start2, size2); | |||
@@ -278,6 +273,7 @@ public: | |||
writer->writeFromAudioSampleBuffer (buffer, start1, size1); | |||
const ScopedLock sl (thumbnailLock); | |||
if (receiver != nullptr) | |||
receiver->addBlock (samplesWritten, buffer, start1, size1); | |||
@@ -330,10 +326,10 @@ private: | |||
TimeSliceThread& timeSliceThread; | |||
std::unique_ptr<AudioFormatWriter> writer; | |||
CriticalSection thumbnailLock; | |||
IncomingDataReceiver* receiver; | |||
int64 samplesWritten; | |||
int samplesPerFlush, flushSampleCounter; | |||
volatile bool isRunning; | |||
IncomingDataReceiver* receiver = {}; | |||
int64 samplesWritten = 0; | |||
int samplesPerFlush = 0, flushSampleCounter = 0; | |||
std::atomic<bool> isRunning { true }; | |||
JUCE_DECLARE_NON_COPYABLE (Buffer) | |||
}; | |||
@@ -1,169 +1,169 @@ | |||
$$CameraApi21 | |||
//============================================================================== | |||
public class CameraDeviceStateCallback extends CameraDevice.StateCallback | |||
{ | |||
private native void cameraDeviceStateClosed (long host, CameraDevice camera); | |||
private native void cameraDeviceStateDisconnected (long host, CameraDevice camera); | |||
private native void cameraDeviceStateError (long host, CameraDevice camera, int error); | |||
private native void cameraDeviceStateOpened (long host, CameraDevice camera); | |||
CameraDeviceStateCallback (long hostToUse) | |||
{ | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onClosed (CameraDevice camera) | |||
{ | |||
cameraDeviceStateClosed (host, camera); | |||
} | |||
@Override | |||
public void onDisconnected (CameraDevice camera) | |||
{ | |||
cameraDeviceStateDisconnected (host, camera); | |||
} | |||
@Override | |||
public void onError (CameraDevice camera, int error) | |||
{ | |||
cameraDeviceStateError (host, camera, error); | |||
} | |||
@Override | |||
public void onOpened (CameraDevice camera) | |||
{ | |||
cameraDeviceStateOpened (host, camera); | |||
} | |||
private long host; | |||
} | |||
//============================================================================== | |||
public class CameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback | |||
{ | |||
private native void cameraCaptureSessionActive (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionClosed (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionConfigureFailed (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionConfigured (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionReady (long host, CameraCaptureSession session); | |||
CameraCaptureSessionStateCallback (long hostToUse) | |||
{ | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onActive (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionActive (host, session); | |||
} | |||
@Override | |||
public void onClosed (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionClosed (host, session); | |||
} | |||
@Override | |||
public void onConfigureFailed (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionConfigureFailed (host, session); | |||
} | |||
@Override | |||
public void onConfigured (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionConfigured (host, session); | |||
} | |||
@Override | |||
public void onReady (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionReady (host, session); | |||
} | |||
private long host; | |||
} | |||
//============================================================================== | |||
public class CameraCaptureSessionCaptureCallback extends CameraCaptureSession.CaptureCallback | |||
{ | |||
private native void cameraCaptureSessionCaptureCompleted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result); | |||
private native void cameraCaptureSessionCaptureFailed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureFailure failure); | |||
private native void cameraCaptureSessionCaptureProgressed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult); | |||
private native void cameraCaptureSessionCaptureStarted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber); | |||
private native void cameraCaptureSessionCaptureSequenceAborted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId); | |||
private native void cameraCaptureSessionCaptureSequenceCompleted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId, long frameNumber); | |||
CameraCaptureSessionCaptureCallback (long hostToUse, boolean shouldBePreview) | |||
{ | |||
host = hostToUse; | |||
preview = shouldBePreview; | |||
} | |||
@Override | |||
public void onCaptureCompleted (CameraCaptureSession session, CaptureRequest request, | |||
TotalCaptureResult result) | |||
{ | |||
cameraCaptureSessionCaptureCompleted (host, preview, session, request, result); | |||
} | |||
@Override | |||
public void onCaptureFailed (CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) | |||
{ | |||
cameraCaptureSessionCaptureFailed (host, preview, session, request, failure); | |||
} | |||
@Override | |||
public void onCaptureProgressed (CameraCaptureSession session, CaptureRequest request, | |||
CaptureResult partialResult) | |||
{ | |||
cameraCaptureSessionCaptureProgressed (host, preview, session, request, partialResult); | |||
} | |||
@Override | |||
public void onCaptureSequenceAborted (CameraCaptureSession session, int sequenceId) | |||
{ | |||
cameraCaptureSessionCaptureSequenceAborted (host, preview, session, sequenceId); | |||
} | |||
@Override | |||
public void onCaptureSequenceCompleted (CameraCaptureSession session, int sequenceId, long frameNumber) | |||
{ | |||
cameraCaptureSessionCaptureSequenceCompleted (host, preview, session, sequenceId, frameNumber); | |||
} | |||
@Override | |||
public void onCaptureStarted (CameraCaptureSession session, CaptureRequest request, long timestamp, | |||
long frameNumber) | |||
{ | |||
cameraCaptureSessionCaptureStarted (host, preview, session, request, timestamp, frameNumber); | |||
} | |||
private long host; | |||
private boolean preview; | |||
} | |||
//============================================================================== | |||
public class JuceOrientationEventListener extends OrientationEventListener | |||
{ | |||
private native void deviceOrientationChanged (long host, int orientation); | |||
public JuceOrientationEventListener (long hostToUse, Context context, int rate) | |||
{ | |||
super (context, rate); | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onOrientationChanged (int orientation) | |||
{ | |||
deviceOrientationChanged (host, orientation); | |||
} | |||
private long host; | |||
} | |||
$$CameraApi21 | |||
//============================================================================== | |||
public class CameraDeviceStateCallback extends CameraDevice.StateCallback | |||
{ | |||
private native void cameraDeviceStateClosed (long host, CameraDevice camera); | |||
private native void cameraDeviceStateDisconnected (long host, CameraDevice camera); | |||
private native void cameraDeviceStateError (long host, CameraDevice camera, int error); | |||
private native void cameraDeviceStateOpened (long host, CameraDevice camera); | |||
CameraDeviceStateCallback (long hostToUse) | |||
{ | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onClosed (CameraDevice camera) | |||
{ | |||
cameraDeviceStateClosed (host, camera); | |||
} | |||
@Override | |||
public void onDisconnected (CameraDevice camera) | |||
{ | |||
cameraDeviceStateDisconnected (host, camera); | |||
} | |||
@Override | |||
public void onError (CameraDevice camera, int error) | |||
{ | |||
cameraDeviceStateError (host, camera, error); | |||
} | |||
@Override | |||
public void onOpened (CameraDevice camera) | |||
{ | |||
cameraDeviceStateOpened (host, camera); | |||
} | |||
private long host; | |||
} | |||
//============================================================================== | |||
public class CameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback | |||
{ | |||
private native void cameraCaptureSessionActive (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionClosed (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionConfigureFailed (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionConfigured (long host, CameraCaptureSession session); | |||
private native void cameraCaptureSessionReady (long host, CameraCaptureSession session); | |||
CameraCaptureSessionStateCallback (long hostToUse) | |||
{ | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onActive (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionActive (host, session); | |||
} | |||
@Override | |||
public void onClosed (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionClosed (host, session); | |||
} | |||
@Override | |||
public void onConfigureFailed (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionConfigureFailed (host, session); | |||
} | |||
@Override | |||
public void onConfigured (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionConfigured (host, session); | |||
} | |||
@Override | |||
public void onReady (CameraCaptureSession session) | |||
{ | |||
cameraCaptureSessionReady (host, session); | |||
} | |||
private long host; | |||
} | |||
//============================================================================== | |||
public class CameraCaptureSessionCaptureCallback extends CameraCaptureSession.CaptureCallback | |||
{ | |||
private native void cameraCaptureSessionCaptureCompleted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result); | |||
private native void cameraCaptureSessionCaptureFailed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureFailure failure); | |||
private native void cameraCaptureSessionCaptureProgressed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult); | |||
private native void cameraCaptureSessionCaptureStarted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber); | |||
private native void cameraCaptureSessionCaptureSequenceAborted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId); | |||
private native void cameraCaptureSessionCaptureSequenceCompleted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId, long frameNumber); | |||
CameraCaptureSessionCaptureCallback (long hostToUse, boolean shouldBePreview) | |||
{ | |||
host = hostToUse; | |||
preview = shouldBePreview; | |||
} | |||
@Override | |||
public void onCaptureCompleted (CameraCaptureSession session, CaptureRequest request, | |||
TotalCaptureResult result) | |||
{ | |||
cameraCaptureSessionCaptureCompleted (host, preview, session, request, result); | |||
} | |||
@Override | |||
public void onCaptureFailed (CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) | |||
{ | |||
cameraCaptureSessionCaptureFailed (host, preview, session, request, failure); | |||
} | |||
@Override | |||
public void onCaptureProgressed (CameraCaptureSession session, CaptureRequest request, | |||
CaptureResult partialResult) | |||
{ | |||
cameraCaptureSessionCaptureProgressed (host, preview, session, request, partialResult); | |||
} | |||
@Override | |||
public void onCaptureSequenceAborted (CameraCaptureSession session, int sequenceId) | |||
{ | |||
cameraCaptureSessionCaptureSequenceAborted (host, preview, session, sequenceId); | |||
} | |||
@Override | |||
public void onCaptureSequenceCompleted (CameraCaptureSession session, int sequenceId, long frameNumber) | |||
{ | |||
cameraCaptureSessionCaptureSequenceCompleted (host, preview, session, sequenceId, frameNumber); | |||
} | |||
@Override | |||
public void onCaptureStarted (CameraCaptureSession session, CaptureRequest request, long timestamp, | |||
long frameNumber) | |||
{ | |||
cameraCaptureSessionCaptureStarted (host, preview, session, request, timestamp, frameNumber); | |||
} | |||
private long host; | |||
private boolean preview; | |||
} | |||
//============================================================================== | |||
public class JuceOrientationEventListener extends OrientationEventListener | |||
{ | |||
private native void deviceOrientationChanged (long host, int orientation); | |||
public JuceOrientationEventListener (long hostToUse, Context context, int rate) | |||
{ | |||
super (context, rate); | |||
host = hostToUse; | |||
} | |||
@Override | |||
public void onOrientationChanged (int orientation) | |||
{ | |||
deviceOrientationChanged (host, orientation); | |||
} | |||
private long host; | |||
} | |||
CameraApi21$$ |
@@ -41,7 +41,7 @@ bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylo | |||
void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&lock); } | |||
//============================================================================== | |||
WaitableEvent::WaitableEvent (const bool useManualReset) noexcept | |||
WaitableEvent::WaitableEvent (bool useManualReset) noexcept | |||
: triggered (false), manualReset (useManualReset) | |||
{ | |||
pthread_cond_init (&condition, 0); | |||
@@ -61,7 +61,7 @@ WaitableEvent::~WaitableEvent() noexcept | |||
pthread_mutex_destroy (&mutex); | |||
} | |||
bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept | |||
bool WaitableEvent::wait (int timeOutMillisecs) const noexcept | |||
{ | |||
pthread_mutex_lock (&mutex); | |||
@@ -152,6 +152,7 @@ void JUCE_CALLTYPE Process::terminate() | |||
bool Process::setMaxNumberOfFileHandles (int newMaxNumber) noexcept | |||
{ | |||
rlimit lim; | |||
if (getrlimit (RLIMIT_NOFILE, &lim) == 0) | |||
{ | |||
if (newMaxNumber <= 0 && lim.rlim_cur == RLIM_INFINITY && lim.rlim_max == RLIM_INFINITY) | |||
@@ -201,8 +202,8 @@ File File::getCurrentWorkingDirectory() | |||
{ | |||
HeapBlock<char> heapBuffer; | |||
char localBuffer [1024]; | |||
char* cwd = getcwd (localBuffer, sizeof (localBuffer) - 1); | |||
char localBuffer[1024]; | |||
auto cwd = getcwd (localBuffer, sizeof (localBuffer) - 1); | |||
size_t bufferSize = 4096; | |||
while (cwd == nullptr && errno == ERANGE) | |||
@@ -221,9 +222,9 @@ bool File::setAsCurrentWorkingDirectory() const | |||
} | |||
#if JUCE_ANDROID | |||
typedef unsigned long juce_sigactionflags_type; | |||
using juce_sigactionflags_type = unsigned long; | |||
#else | |||
typedef int juce_sigactionflags_type; | |||
using juce_sigactionflags_type = int; | |||
#endif | |||
//============================================================================== | |||
@@ -245,11 +246,11 @@ int juce_siginterrupt (int sig, int flag) | |||
namespace | |||
{ | |||
#if JUCE_LINUX || (JUCE_IOS && ! __DARWIN_ONLY_64_BIT_INO_T) // (this iOS stuff is to avoid a simulator bug) | |||
typedef struct stat64 juce_statStruct; | |||
#define JUCE_STAT stat64 | |||
using juce_statStruct = struct stat64; | |||
#define JUCE_STAT stat64 | |||
#else | |||
typedef struct stat juce_statStruct; | |||
#define JUCE_STAT stat | |||
using juce_statStruct = struct stat; | |||
#define JUCE_STAT stat | |||
#endif | |||
bool juce_stat (const String& fileName, juce_statStruct& info) | |||
@@ -278,8 +279,8 @@ namespace | |||
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; } | |||
#endif | |||
void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize, | |||
Time* const modTime, Time* const creationTime, bool* const isReadOnly) | |||
void updateStatInfoForFile (const String& path, bool* isDir, int64* fileSize, | |||
Time* modTime, Time* creationTime, bool* isReadOnly) | |||
{ | |||
if (isDir != nullptr || fileSize != nullptr || modTime != nullptr || creationTime != nullptr) | |||
{ | |||
@@ -344,7 +345,7 @@ uint64 File::getFileIdentifier() const | |||
static bool hasEffectiveRootFilePermissions() | |||
{ | |||
#if JUCE_LINUX | |||
return (geteuid() == 0); | |||
return geteuid() == 0; | |||
#else | |||
return false; | |||
#endif | |||
@@ -475,7 +476,7 @@ int64 juce_fileSetPosition (void* handle, int64 pos) | |||
void FileInputStream::openHandle() | |||
{ | |||
const int f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644); | |||
auto f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644); | |||
if (f != -1) | |||
fileHandle = fdToVoidPointer (f); | |||
@@ -489,7 +490,7 @@ FileInputStream::~FileInputStream() | |||
close (getFD (fileHandle)); | |||
} | |||
size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes) | |||
size_t FileInputStream::readInternal (void* buffer, size_t numBytes) | |||
{ | |||
ssize_t result = 0; | |||
@@ -512,7 +513,7 @@ void FileOutputStream::openHandle() | |||
{ | |||
if (file.exists()) | |||
{ | |||
const int f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644); | |||
auto f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644); | |||
if (f != -1) | |||
{ | |||
@@ -535,7 +536,7 @@ void FileOutputStream::openHandle() | |||
} | |||
else | |||
{ | |||
const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644); | |||
auto f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644); | |||
if (f != -1) | |||
fileHandle = fdToVoidPointer (f); | |||
@@ -553,19 +554,17 @@ void FileOutputStream::closeHandle() | |||
} | |||
} | |||
ssize_t FileOutputStream::writeInternal (const void* const data, const size_t numBytes) | |||
ssize_t FileOutputStream::writeInternal (const void* data, size_t numBytes) | |||
{ | |||
ssize_t result = 0; | |||
if (fileHandle == 0) | |||
return 0; | |||
if (fileHandle != 0) | |||
{ | |||
result = ::write (getFD (fileHandle), data, numBytes); | |||
auto result = ::write (getFD (fileHandle), data, numBytes); | |||
if (result == -1) | |||
status = getResultForErrno(); | |||
} | |||
if (result == -1) | |||
status = getResultForErrno(); | |||
return result; | |||
return (ssize_t) result; | |||
} | |||
#ifndef JUCE_ANDROID | |||
@@ -588,7 +587,7 @@ Result FileOutputStream::truncate() | |||
//============================================================================== | |||
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue) | |||
{ | |||
if (const char* s = ::getenv (name.toUTF8())) | |||
if (auto s = ::getenv (name.toUTF8())) | |||
return String::fromUTF8 (s); | |||
return defaultValue; | |||
@@ -601,7 +600,7 @@ void MemoryMappedFile::openInternal (const File& file, AccessMode mode, bool exc | |||
if (range.getStart() > 0) | |||
{ | |||
const long pageSize = sysconf (_SC_PAGE_SIZE); | |||
auto pageSize = sysconf (_SC_PAGE_SIZE); | |||
range.setStart (range.getStart() - (range.getStart() % pageSize)); | |||
} | |||
@@ -649,7 +648,7 @@ File juce_getExecutableFile() | |||
{ | |||
Dl_info exeInfo; | |||
void* localSymbol = (void*) juce_getExecutableFile; | |||
auto localSymbol = (void*) juce_getExecutableFile; | |||
dladdr (localSymbol, &exeInfo); | |||
return CharPointer_UTF8 (exeInfo.dli_fname); | |||
} | |||
@@ -664,6 +663,7 @@ File juce_getExecutableFile() | |||
int64 File::getBytesFreeOnVolume() const | |||
{ | |||
struct statfs buf; | |||
if (juce_doStatFS (*this, buf)) | |||
return (int64) buf.f_bsize * (int64) buf.f_bavail; // Note: this returns space available to non-super user | |||
@@ -673,6 +673,7 @@ int64 File::getBytesFreeOnVolume() const | |||
int64 File::getVolumeTotalSize() const | |||
{ | |||
struct statfs buf; | |||
if (juce_doStatFS (*this, buf)) | |||
return (int64) buf.f_bsize * (int64) buf.f_blocks; | |||
@@ -686,11 +687,11 @@ String File::getVolumeLabel() const | |||
{ | |||
u_int32_t length; | |||
attrreference_t mountPointRef; | |||
char mountPointSpace [MAXPATHLEN]; | |||
char mountPointSpace[MAXPATHLEN]; | |||
} attrBuf; | |||
struct attrlist attrList; | |||
zerostruct (attrList); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct) | |||
zerostruct (attrList); // (can't use "= {}" on this object because it's a C struct) | |||
attrList.bitmapcount = ATTR_BIT_MAP_COUNT; | |||
attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME; | |||
@@ -702,7 +703,7 @@ String File::getVolumeLabel() const | |||
return String::fromUTF8 (((const char*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset, | |||
(int) attrBuf.mountPointRef.attr_length); | |||
const File parent (f.getParentDirectory()); | |||
auto parent = f.getParentDirectory(); | |||
if (f == parent) | |||
break; | |||
@@ -719,7 +720,7 @@ int File::getVolumeSerialNumber() const | |||
int result = 0; | |||
/* int fd = open (getFullPathName().toUTF8(), O_RDONLY | O_NONBLOCK); | |||
char info [512]; | |||
char info[512]; | |||
#ifndef HDIO_GET_IDENTITY | |||
#define HDIO_GET_IDENTITY 0x030d | |||
@@ -748,12 +749,12 @@ String juce_getOutputFromCommand (const String&); | |||
String juce_getOutputFromCommand (const String& command) | |||
{ | |||
// slight bodge here, as we just pipe the output into a temp file and read it... | |||
const File tempFile (File::getSpecialLocation (File::tempDirectory) | |||
.getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false)); | |||
auto tempFile = File::getSpecialLocation (File::tempDirectory) | |||
.getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false); | |||
juce_runSystemCommand (command + " > " + tempFile.getFullPathName()); | |||
String result (tempFile.loadFileAsString()); | |||
auto result = tempFile.loadFileAsString(); | |||
tempFile.deleteFile(); | |||
return result; | |||
} | |||
@@ -764,12 +765,9 @@ String juce_getOutputFromCommand (const String& command) | |||
class InterProcessLock::Pimpl | |||
{ | |||
public: | |||
Pimpl (const String&, int) | |||
: handle (1), refCount (1) // On iOS just fake success.. | |||
{ | |||
} | |||
Pimpl (const String&, int) {} | |||
int handle, refCount; | |||
int handle = 1, refCount = 1; // On iOS just fake success.. | |||
}; | |||
#else | |||
@@ -777,8 +775,7 @@ public: | |||
class InterProcessLock::Pimpl | |||
{ | |||
public: | |||
Pimpl (const String& lockName, const int timeOutMillisecs) | |||
: handle (0), refCount (1) | |||
Pimpl (const String& lockName, int timeOutMillisecs) | |||
{ | |||
#if JUCE_MAC | |||
if (! createLockFile (File ("~/Library/Caches/com.juce.locks").getChildFile (lockName), timeOutMillisecs)) | |||
@@ -787,6 +784,7 @@ public: | |||
#else | |||
File tempFolder ("/var/tmp"); | |||
if (! tempFolder.isDirectory()) | |||
tempFolder = "/tmp"; | |||
@@ -799,7 +797,7 @@ public: | |||
closeFile(); | |||
} | |||
bool createLockFile (const File& file, const int timeOutMillisecs) | |||
bool createLockFile (const File& file, int timeOutMillisecs) | |||
{ | |||
file.create(); | |||
handle = open (file.getFullPathName().toUTF8(), O_RDWR); | |||
@@ -812,16 +810,16 @@ public: | |||
fl.l_whence = SEEK_SET; | |||
fl.l_type = F_WRLCK; | |||
const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
auto endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
for (;;) | |||
{ | |||
const int result = fcntl (handle, F_SETLK, &fl); | |||
auto result = fcntl (handle, F_SETLK, &fl); | |||
if (result >= 0) | |||
return true; | |||
const int error = errno; | |||
auto error = errno; | |||
if (error != EINTR) | |||
{ | |||
@@ -859,7 +857,7 @@ public: | |||
} | |||
} | |||
int handle, refCount; | |||
int handle = 0, refCount = 1; | |||
}; | |||
#endif | |||
@@ -871,7 +869,7 @@ InterProcessLock::~InterProcessLock() | |||
{ | |||
} | |||
bool InterProcessLock::enter (const int timeOutMillisecs) | |||
bool InterProcessLock::enter (int timeOutMillisecs) | |||
{ | |||
const ScopedLock sl (lock); | |||
@@ -964,7 +962,6 @@ void Thread::launchThread() | |||
if (pthread_attr_init (&attr) == 0) | |||
{ | |||
attrPtr = &attr; | |||
pthread_attr_setstacksize (attrPtr, threadStackSize); | |||
} | |||
@@ -1054,7 +1051,7 @@ void JUCE_CALLTYPE Thread::yield() | |||
#define SUPPORT_AFFINITIES 1 | |||
#endif | |||
void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) | |||
void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (uint32 affinityMask) | |||
{ | |||
#if SUPPORT_AFFINITIES | |||
cpu_set_t affinity; | |||
@@ -1109,7 +1106,7 @@ void* DynamicLibrary::getFunction (const String& functionName) noexcept | |||
//============================================================================== | |||
static inline String readPosixConfigFileValue (const char* file, const char* const key) | |||
static inline String readPosixConfigFileValue (const char* file, const char* key) | |||
{ | |||
StringArray lines; | |||
File (file).readLines (lines); | |||
@@ -1267,7 +1264,7 @@ bool ChildProcess::start (const StringArray& args, int streamFlags) | |||
//============================================================================== | |||
struct HighResolutionTimer::Pimpl | |||
{ | |||
Pimpl (HighResolutionTimer& t) : owner (t), thread (0), destroyThread (false), isRunning (false) | |||
Pimpl (HighResolutionTimer& t) : owner (t) | |||
{ | |||
pthread_condattr_t attr; | |||
pthread_condattr_init (&attr); | |||
@@ -1338,15 +1335,13 @@ struct HighResolutionTimer::Pimpl | |||
} | |||
HighResolutionTimer& owner; | |||
int volatile periodMs; | |||
std::atomic<int> periodMs; | |||
private: | |||
pthread_t thread; | |||
pthread_t thread = {}; | |||
pthread_cond_t stopCond; | |||
pthread_mutex_t timerMutex; | |||
bool volatile destroyThread; | |||
bool volatile isRunning; | |||
std::atomic<bool> destroyThread { false }, isRunning { false }; | |||
static void* timerThread (void* param) | |||
{ | |||
@@ -1369,7 +1364,7 @@ private: | |||
void timerThread() | |||
{ | |||
int lastPeriod = periodMs; | |||
auto lastPeriod = periodMs.load(); | |||
Clock clock (lastPeriod); | |||
pthread_mutex_lock (&timerMutex); | |||
@@ -1385,15 +1380,16 @@ private: | |||
if (isRunning) | |||
owner.hiResTimerCallback(); | |||
if (lastPeriod != periodMs) | |||
auto newPeriod = periodMs.load(); | |||
if (lastPeriod != newPeriod) | |||
{ | |||
lastPeriod = periodMs; | |||
lastPeriod = newPeriod; | |||
clock = Clock (lastPeriod); | |||
} | |||
} | |||
periodMs = 0; | |||
pthread_mutex_unlock (&timerMutex); | |||
pthread_exit (nullptr); | |||
} | |||
@@ -1421,7 +1417,7 @@ private: | |||
uint64_t time, delta; | |||
mach_timebase_info_data_t timebase; | |||
bool hasExpired(struct timespec& time_left) noexcept | |||
bool hasExpired (struct timespec& time_left) noexcept | |||
{ | |||
uint64_t now = mach_absolute_time(); | |||
@@ -1457,11 +1453,11 @@ private: | |||
uint64 time, delta; | |||
bool hasExpired(struct timespec& expiryTime) noexcept | |||
bool hasExpired (struct timespec& expiryTime) noexcept | |||
{ | |||
struct timespec t; | |||
clock_gettime (CLOCK_MONOTONIC, &t); | |||
uint64 now = (uint64) (1000000000 * (int64) t.tv_sec + (int64) t.tv_nsec); | |||
auto now = (uint64) (1000000000 * (int64) t.tv_sec + (int64) t.tv_nsec); | |||
if (now < time) | |||
{ | |||
@@ -94,10 +94,10 @@ namespace SocketHelpers | |||
: setOption (handle, IPPROTO_TCP, TCP_NODELAY, (int) 1)); | |||
} | |||
static void closeSocket (volatile int& handle, CriticalSection& readLock, | |||
bool isListener, int portNumber, bool& connected) noexcept | |||
static void closeSocket (std::atomic<int>& handle, CriticalSection& readLock, | |||
bool isListener, int portNumber, std::atomic<bool>& connected) noexcept | |||
{ | |||
const SocketHandle h = handle; | |||
const SocketHandle h = handle.load(); | |||
handle = -1; | |||
#if JUCE_WINDOWS | |||
@@ -187,8 +187,8 @@ namespace SocketHelpers | |||
} | |||
static int readSocket (SocketHandle handle, | |||
void* const destBuffer, const int maxBytesToRead, | |||
bool volatile& connected, | |||
void* destBuffer, int maxBytesToRead, | |||
std::atomic<bool>& connected, | |||
bool blockUntilSpecifiedAmountHasArrived, | |||
CriticalSection& readLock, | |||
String* senderIP = nullptr, | |||
@@ -242,8 +242,8 @@ namespace SocketHelpers | |||
return (int) bytesRead; | |||
} | |||
static int waitForReadiness (const volatile int& handle, CriticalSection& readLock, | |||
const bool forReading, const int timeoutMsecs) noexcept | |||
static int waitForReadiness (std::atomic<int>& handle, CriticalSection& readLock, | |||
bool forReading, int timeoutMsecs) noexcept | |||
{ | |||
// avoid race-condition | |||
CriticalSection::ScopedTryLockType lock (readLock); | |||
@@ -251,7 +251,7 @@ namespace SocketHelpers | |||
if (! lock.isLocked()) | |||
return -1; | |||
int h = handle; | |||
int h = handle.load(); | |||
struct timeval timeout; | |||
struct timeval* timeoutp; | |||
@@ -293,7 +293,7 @@ namespace SocketHelpers | |||
#endif | |||
// we are closing | |||
if (handle < 0) | |||
if (handle.load() < 0) | |||
return -1; | |||
{ | |||
@@ -308,7 +308,7 @@ namespace SocketHelpers | |||
return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; | |||
} | |||
static bool setSocketBlockingState (SocketHandle handle, const bool shouldBlock) noexcept | |||
static bool setSocketBlockingState (SocketHandle handle, bool shouldBlock) noexcept | |||
{ | |||
#if JUCE_WINDOWS | |||
u_long nonBlocking = shouldBlock ? 0 : (u_long) 1; | |||
@@ -328,7 +328,7 @@ namespace SocketHelpers | |||
#endif | |||
} | |||
static addrinfo* getAddressInfo (const bool isDatagram, const String& hostName, int portNumber) | |||
static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber) | |||
{ | |||
struct addrinfo hints; | |||
zerostruct (hints); | |||
@@ -345,11 +345,11 @@ namespace SocketHelpers | |||
return nullptr; | |||
} | |||
static bool connectSocket (int volatile& handle, | |||
static bool connectSocket (std::atomic<int>& handle, | |||
CriticalSection& readLock, | |||
const String& hostName, | |||
const int portNumber, | |||
const int timeOutMillisecs) noexcept | |||
int portNumber, | |||
int timeOutMillisecs) noexcept | |||
{ | |||
bool success = false; | |||
@@ -373,7 +373,7 @@ namespace SocketHelpers | |||
if (errno == EINPROGRESS) | |||
#endif | |||
{ | |||
const volatile int cvHandle = (int) newHandle; | |||
std::atomic<int> cvHandle { (int) newHandle }; | |||
if (waitForReadiness (cvHandle, readLock, false, timeOutMillisecs) == 1) | |||
success = true; | |||
@@ -454,14 +454,14 @@ StreamingSocket::~StreamingSocket() | |||
} | |||
//============================================================================== | |||
int StreamingSocket::read (void* destBuffer, const int maxBytesToRead, bool shouldBlock) | |||
int StreamingSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock) | |||
{ | |||
return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, | |||
connected, shouldBlock, readLock) | |||
: -1; | |||
} | |||
int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite) | |||
int StreamingSocket::write (const void* sourceBuffer, int numBytesToWrite) | |||
{ | |||
if (isListener || ! connected) | |||
return -1; | |||
@@ -470,20 +470,19 @@ int StreamingSocket::write (const void* sourceBuffer, const int numBytesToWrite) | |||
} | |||
//============================================================================== | |||
int StreamingSocket::waitUntilReady (const bool readyForReading, | |||
const int timeoutMsecs) const | |||
int StreamingSocket::waitUntilReady (bool readyForReading, int timeoutMsecs) | |||
{ | |||
return connected ? SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs) | |||
: -1; | |||
} | |||
//============================================================================== | |||
bool StreamingSocket::bindToPort (const int port) | |||
bool StreamingSocket::bindToPort (int port) | |||
{ | |||
return bindToPort (port, String()); | |||
} | |||
bool StreamingSocket::bindToPort (const int port, const String& addr) | |||
bool StreamingSocket::bindToPort (int port, const String& addr) | |||
{ | |||
jassert (SocketHelpers::isValidPortNumber (port)); | |||
@@ -495,9 +494,7 @@ int StreamingSocket::getBoundPort() const noexcept | |||
return SocketHelpers::getBoundPort (handle); | |||
} | |||
bool StreamingSocket::connect (const String& remoteHostName, | |||
const int remotePortNumber, | |||
const int timeOutMillisecs) | |||
bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumber, int timeOutMillisecs) | |||
{ | |||
jassert (SocketHelpers::isValidPortNumber (remotePortNumber)); | |||
@@ -537,7 +534,7 @@ void StreamingSocket::close() | |||
} | |||
//============================================================================== | |||
bool StreamingSocket::createListener (const int newPortNumber, const String& localHostName) | |||
bool StreamingSocket::createListener (int newPortNumber, const String& localHostName) | |||
{ | |||
jassert (SocketHelpers::isValidPortNumber (newPortNumber)); | |||
@@ -633,18 +630,18 @@ void DatagramSocket::shutdown() | |||
if (handle < 0) | |||
return; | |||
auto copyOfHandle = handle; | |||
std::atomic<int> handleCopy { handle.load() }; | |||
handle = -1; | |||
bool connected = false; | |||
SocketHelpers::closeSocket (copyOfHandle, readLock, false, 0, connected); | |||
std::atomic<bool> connected { false }; | |||
SocketHelpers::closeSocket (handleCopy, readLock, false, 0, connected); | |||
} | |||
bool DatagramSocket::bindToPort (const int port) | |||
bool DatagramSocket::bindToPort (int port) | |||
{ | |||
return bindToPort (port, String()); | |||
} | |||
bool DatagramSocket::bindToPort (const int port, const String& addr) | |||
bool DatagramSocket::bindToPort (int port, const String& addr) | |||
{ | |||
jassert (SocketHelpers::isValidPortNumber (port)); | |||
@@ -664,8 +661,7 @@ int DatagramSocket::getBoundPort() const noexcept | |||
} | |||
//============================================================================== | |||
int DatagramSocket::waitUntilReady (const bool readyForReading, | |||
const int timeoutMsecs) const | |||
int DatagramSocket::waitUntilReady (bool readyForReading, int timeoutMsecs) | |||
{ | |||
if (handle < 0) | |||
return -1; | |||
@@ -678,7 +674,7 @@ int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock | |||
if (handle < 0 || ! isBound) | |||
return -1; | |||
bool connected = true; | |||
std::atomic<bool> connected { true }; | |||
SocketHelpers::setSocketBlockingState (handle, shouldBlock); | |||
return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, | |||
@@ -690,7 +686,7 @@ int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock | |||
if (handle < 0 || ! isBound) | |||
return -1; | |||
bool connected = true; | |||
std::atomic<bool> connected { true }; | |||
SocketHelpers::setSocketBlockingState (handle, shouldBlock); | |||
return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected, | |||
@@ -122,8 +122,7 @@ public: | |||
If the socket is ready on return, this returns 1. If it times-out before | |||
the socket becomes ready, it returns 0. If an error occurs, it returns -1. | |||
*/ | |||
int waitUntilReady (bool readyForReading, | |||
int timeoutMsecs) const; | |||
int waitUntilReady (bool readyForReading, int timeoutMsecs); | |||
/** Reads bytes from the socket. | |||
@@ -177,8 +176,9 @@ public: | |||
private: | |||
//============================================================================== | |||
String hostName; | |||
int volatile portNumber = 0, handle = -1; | |||
bool connected = false, isListener = false; | |||
std::atomic<int> portNumber { 0 }, handle { -1 }; | |||
std::atomic<bool> connected { false }; | |||
bool isListener = false; | |||
mutable CriticalSection readLock; | |||
StreamingSocket (const String& hostname, int portNumber, int handle); | |||
@@ -263,8 +263,7 @@ public: | |||
If the socket is ready on return, this returns 1. If it times-out before | |||
the socket becomes ready, it returns 0. If an error occurs, it returns -1. | |||
*/ | |||
int waitUntilReady (bool readyForReading, | |||
int timeoutMsecs) const; | |||
int waitUntilReady (bool readyForReading, int timeoutMsecs); | |||
/** Reads bytes from the socket. | |||
@@ -320,19 +319,16 @@ public: | |||
//============================================================================== | |||
/** Join a multicast group. | |||
@returns true if it succeeds. | |||
*/ | |||
bool joinMulticast (const String& multicastIPAddress); | |||
/** Leave a multicast group. | |||
@returns true if it succeeds. | |||
*/ | |||
bool leaveMulticast (const String& multicastIPAddress); | |||
/** Enables or disables multicast loopback. | |||
@returns true if it succeeds. | |||
*/ | |||
bool setMulticastLoopbackEnabled (bool enableLoopback); | |||
@@ -350,7 +346,7 @@ public: | |||
private: | |||
//============================================================================== | |||
int handle = -1; | |||
std::atomic<int> handle { -1 }; | |||
bool isBound = false; | |||
String lastBindAddress, lastServerHost; | |||
int lastServerPort = -1; | |||
@@ -23,9 +23,8 @@ | |||
namespace juce | |||
{ | |||
class ThreadPool::ThreadPoolThread : public Thread | |||
struct ThreadPool::ThreadPoolThread : public Thread | |||
{ | |||
public: | |||
ThreadPoolThread (ThreadPool& p, size_t stackSize) | |||
: Thread ("Pool", stackSize), pool (p) | |||
{ | |||
@@ -38,7 +37,7 @@ public: | |||
wait (500); | |||
} | |||
ThreadPoolJob* volatile currentJob = nullptr; | |||
std::atomic<ThreadPoolJob*> currentJob { nullptr }; | |||
ThreadPool& pool; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread) | |||
@@ -85,7 +84,7 @@ void ThreadPoolJob::removeListener (Thread::Listener* listener) | |||
ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob() | |||
{ | |||
if (auto* t = dynamic_cast<ThreadPool::ThreadPoolThread*> (Thread::getCurrentThread())) | |||
return t->currentJob; | |||
return t->currentJob.load(); | |||
return nullptr; | |||
} | |||
@@ -24,8 +24,6 @@ namespace juce | |||
{ | |||
class ThreadPool; | |||
class ThreadPoolThread; | |||
//============================================================================== | |||
/** | |||
@@ -134,7 +132,6 @@ public: | |||
//============================================================================== | |||
private: | |||
friend class ThreadPool; | |||
friend class ThreadPoolThread; | |||
String jobName; | |||
ThreadPool* pool = nullptr; | |||
bool shouldStop = false, isActive = false, shouldBeDeleted = false; | |||
@@ -323,9 +320,9 @@ private: | |||
//============================================================================== | |||
Array<ThreadPoolJob*> jobs; | |||
class ThreadPoolThread; | |||
struct ThreadPoolThread; | |||
friend class ThreadPoolJob; | |||
friend class ThreadPoolThread; | |||
friend struct ThreadPoolThread; | |||
friend struct ContainerDeletePolicy<ThreadPoolThread>; | |||
OwnedArray<ThreadPoolThread> threads; | |||
@@ -155,7 +155,7 @@ public: | |||
} | |||
WaitableEvent finished; | |||
void* volatile result = nullptr; | |||
std::atomic<void*> result { nullptr }; | |||
private: | |||
MessageCallbackFunction* const func; | |||
@@ -177,7 +177,7 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* cons | |||
if (message->post()) | |||
{ | |||
message->finished.wait(); | |||
return message->result; | |||
return message->result.load(); | |||
} | |||
jassertfalse; // the OS message queue failed to send the message! | |||