Browse Source

Update juce

tags/1.9.4
falkTX 12 years ago
parent
commit
be5dfc39ea
79 changed files with 1470 additions and 881 deletions
  1. +172
    -62
      source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp
  2. +97
    -19
      source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
  3. +506
    -363
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  4. +44
    -2
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  5. +4
    -0
      source/modules/juce_audio_basics/juce_audio_basics.cpp
  6. +4
    -2
      source/modules/juce_audio_basics/midi/juce_MidiFile.cpp
  7. +3
    -1
      source/modules/juce_audio_basics/midi/juce_MidiFile.h
  8. +3
    -2
      source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp
  9. +9
    -5
      source/modules/juce_audio_basics/midi/juce_MidiMessage.h
  10. +1
    -1
      source/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp
  11. +5
    -5
      source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp
  12. +2
    -1
      source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h
  13. +2
    -2
      source/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp
  14. +1
    -1
      source/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp
  15. +23
    -16
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  16. +9
    -0
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  17. +5
    -6
      source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  18. +4
    -4
      source/modules/juce_audio_devices/native/juce_android_Audio.cpp
  19. +4
    -6
      source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  20. +2
    -2
      source/modules/juce_audio_devices/native/juce_ios_Audio.cpp
  21. +7
    -6
      source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  22. +2
    -2
      source/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm
  23. +10
    -9
      source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  24. +2
    -2
      source/modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp
  25. +6
    -18
      source/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp
  26. +3
    -3
      source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
  27. +1
    -1
      source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp
  28. +3
    -2
      source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp
  29. +21
    -6
      source/modules/juce_audio_formats/codecs/juce_MP3AudioFormat.cpp
  30. +2
    -6
      source/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp
  31. +7
    -5
      source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  32. +1
    -0
      source/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp
  33. +1
    -0
      source/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.h
  34. +15
    -16
      source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp
  35. +3
    -3
      source/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp
  36. +1
    -1
      source/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp
  37. +4
    -4
      source/modules/juce_audio_formats/sampler/juce_Sampler.cpp
  38. +2
    -2
      source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  39. +3
    -3
      source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp
  40. +2
    -2
      source/modules/juce_audio_processors/format_types/juce_VST3Common.h
  41. +10
    -4
      source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  42. +3
    -3
      source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  43. +4
    -4
      source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
  44. +1
    -1
      source/modules/juce_core/files/juce_File.cpp
  45. +34
    -1
      source/modules/juce_core/maths/juce_Range.h
  46. +7
    -2
      source/modules/juce_core/memory/juce_MemoryBlock.cpp
  47. +6
    -3
      source/modules/juce_core/memory/juce_MemoryBlock.h
  48. +1
    -6
      source/modules/juce_core/network/juce_MACAddress.h
  49. +85
    -75
      source/modules/juce_core/network/juce_URL.cpp
  50. +33
    -14
      source/modules/juce_core/network/juce_URL.h
  51. +1
    -0
      source/modules/juce_core/system/juce_SystemStats.h
  52. +6
    -14
      source/modules/juce_core/threads/juce_ReadWriteLock.cpp
  53. +2
    -0
      source/modules/juce_core/threads/juce_ReadWriteLock.h
  54. +1
    -2
      source/modules/juce_data_structures/values/juce_Value.h
  55. +1
    -1
      source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp
  56. +1
    -1
      source/modules/juce_events/messages/juce_MessageManager.h
  57. +0
    -26
      source/modules/juce_events/timers/juce_Timer.cpp
  58. +9
    -0
      source/modules/juce_graphics/fonts/juce_CustomTypeface.h
  59. +11
    -6
      source/modules/juce_graphics/geometry/juce_Path.cpp
  60. +13
    -2
      source/modules/juce_graphics/geometry/juce_Path.h
  61. +54
    -45
      source/modules/juce_graphics/native/juce_RenderingHelpers.h
  62. +2
    -1
      source/modules/juce_graphics/native/juce_win32_Fonts.cpp
  63. +4
    -2
      source/modules/juce_gui_basics/buttons/juce_Button.h
  64. +1
    -1
      source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp
  65. +10
    -16
      source/modules/juce_gui_basics/buttons/juce_TextButton.cpp
  66. +7
    -7
      source/modules/juce_gui_basics/buttons/juce_TextButton.h
  67. +9
    -4
      source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp
  68. +10
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  69. +1
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h
  70. +2
    -1
      source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp
  71. +6
    -2
      source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  72. +111
    -30
      source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  73. +1
    -1
      source/modules/juce_gui_basics/widgets/juce_Slider.cpp
  74. +9
    -2
      source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp
  75. +2
    -1
      source/modules/juce_gui_basics/windows/juce_CallOutBox.h
  76. +4
    -4
      source/modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp
  77. +4
    -4
      source/modules/juce_gui_extra/native/juce_linux_WebBrowserComponent.cpp
  78. +4
    -2
      source/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm
  79. +4
    -2
      source/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp

+ 172
- 62
source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp View File

@@ -46,8 +46,15 @@ AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) noexcept
{
allocateData();
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
if (other.isClear)
{
clear();
}
else
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
}
}
}
@@ -66,6 +73,7 @@ void AudioSampleBuffer::allocateData()
}
channels [numChannels] = nullptr;
isClear = false;
}
AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
@@ -85,7 +93,8 @@ AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
const int numSamples) noexcept
: numChannels (numChans),
size (numSamples),
allocatedBytes (0)
allocatedBytes (0),
isClear (false)
{
jassert (numChans > 0);
allocateChannels (dataToReferTo, startSample);
@@ -104,6 +113,7 @@ void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
size = newNumSamples;
allocateChannels (dataToReferTo, 0);
jassert (! isClear);
}
void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset)
@@ -128,6 +138,7 @@ void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int
}
channels [numChannels] = nullptr;
isClear = false;
}
AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) noexcept
@@ -136,8 +147,15 @@ AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other)
{
setSize (other.getNumChannels(), other.getNumSamples(), false, false, false);
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
if (other.isClear)
{
clear();
}
else
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
}
}
return *this;
@@ -165,13 +183,13 @@ void AudioSampleBuffer::setSize (const int newNumChannels,
if (keepExistingContent)
{
HeapBlock <char, true> newData;
newData.allocate (newTotalBytes, clearExtraSpace);
HeapBlock<char, true> newData;
newData.allocate (newTotalBytes, clearExtraSpace || isClear);
const size_t numSamplesToCopy = (size_t) jmin (newNumSamples, size);
float** const newChannels = reinterpret_cast <float**> (newData.getData());
float* newChan = reinterpret_cast <float*> (newData + channelListSize);
float** const newChannels = reinterpret_cast<float**> (newData.getData());
float* newChan = reinterpret_cast<float*> (newData + channelListSize);
for (int j = 0; j < newNumChannels; ++j)
{
@@ -179,9 +197,12 @@ void AudioSampleBuffer::setSize (const int newNumChannels,
newChan += allocatedSamplesPerChannel;
}
const int numChansToCopy = jmin (numChannels, newNumChannels);
for (int i = 0; i < numChansToCopy; ++i)
FloatVectorOperations::copy (newChannels[i], channels[i], (int) numSamplesToCopy);
if (! isClear)
{
const int numChansToCopy = jmin (numChannels, newNumChannels);
for (int i = 0; i < numChansToCopy; ++i)
FloatVectorOperations::copy (newChannels[i], channels[i], (int) numSamplesToCopy);
}
allocatedData.swapWith (newData);
allocatedBytes = newTotalBytes;
@@ -191,17 +212,17 @@ void AudioSampleBuffer::setSize (const int newNumChannels,
{
if (avoidReallocating && allocatedBytes >= newTotalBytes)
{
if (clearExtraSpace)
if (clearExtraSpace || isClear)
allocatedData.clear (newTotalBytes);
}
else
{
allocatedBytes = newTotalBytes;
allocatedData.allocate (newTotalBytes, clearExtraSpace);
channels = reinterpret_cast <float**> (allocatedData.getData());
allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear);
channels = reinterpret_cast<float**> (allocatedData.getData());
}
float* chan = reinterpret_cast <float*> (allocatedData + channelListSize);
float* chan = reinterpret_cast<float*> (allocatedData + channelListSize);
for (int i = 0; i < newNumChannels; ++i)
{
channels[i] = chan;
@@ -217,8 +238,13 @@ void AudioSampleBuffer::setSize (const int newNumChannels,
void AudioSampleBuffer::clear() noexcept
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::clear (channels[i], size);
if (! isClear)
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::clear (channels[i], size);
isClear = true;
}
}
void AudioSampleBuffer::clear (const int startSample,
@@ -226,8 +252,14 @@ void AudioSampleBuffer::clear (const int startSample,
{
jassert (startSample >= 0 && startSample + numSamples <= size);
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::clear (channels[i] + startSample, numSamples);
if (! isClear)
{
if (startSample == 0 && numSamples == size)
isClear = true;
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::clear (channels[i] + startSample, numSamples);
}
}
void AudioSampleBuffer::clear (const int channel,
@@ -237,7 +269,31 @@ void AudioSampleBuffer::clear (const int channel,
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
FloatVectorOperations::clear (channels [channel] + startSample, numSamples);
if (! isClear)
FloatVectorOperations::clear (channels [channel] + startSample, numSamples);
}
float AudioSampleBuffer::getSample (int channel, int index) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (isPositiveAndBelow (index, size));
return *(channels [channel] + index);
}
void AudioSampleBuffer::setSample (int channel, int index, float newValue) noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (isPositiveAndBelow (index, size));
*(channels [channel] + index) = newValue;
isClear = false;
}
void AudioSampleBuffer::addSample (int channel, int index, float valueToAdd) noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (isPositiveAndBelow (index, size));
*(channels [channel] + index) += valueToAdd;
isClear = false;
}
void AudioSampleBuffer::applyGain (const int channel,
@@ -248,7 +304,7 @@ void AudioSampleBuffer::applyGain (const int channel,
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (gain != 1.0f)
if (gain != 1.0f && ! isClear)
{
float* const d = channels [channel] + startSample;
@@ -265,22 +321,25 @@ void AudioSampleBuffer::applyGainRamp (const int channel,
float startGain,
float endGain) noexcept
{
if (startGain == endGain)
if (! isClear)
{
applyGain (channel, startSample, numSamples, startGain);
}
else
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (startGain == endGain)
{
applyGain (channel, startSample, numSamples, startGain);
}
else
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
const float increment = (endGain - startGain) / numSamples;
float* d = channels [channel] + startSample;
const float increment = (endGain - startGain) / numSamples;
float* d = channels [channel] + startSample;
while (--numSamples >= 0)
{
*d++ *= startGain;
startGain += increment;
while (--numSamples >= 0)
{
*d++ *= startGain;
startGain += increment;
}
}
}
}
@@ -317,15 +376,27 @@ void AudioSampleBuffer::addFrom (const int destChannel,
jassert (isPositiveAndBelow (sourceChannel, source.numChannels));
jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size);
if (gain != 0.0f && numSamples > 0)
if (gain != 0.0f && numSamples > 0 && ! source.isClear)
{
float* const d = channels [destChannel] + destStartSample;
const float* const s = source.channels [sourceChannel] + sourceStartSample;
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, s, gain, numSamples);
if (isClear)
{
isClear = false;
if (gain != 1.0f)
FloatVectorOperations::copyWithMultiply (d, s, gain, numSamples);
else
FloatVectorOperations::copy (d, s, numSamples);
}
else
FloatVectorOperations::add (d, s, numSamples);
{
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, s, gain, numSamples);
else
FloatVectorOperations::add (d, s, numSamples);
}
}
}
@@ -343,10 +414,22 @@ void AudioSampleBuffer::addFrom (const int destChannel,
{
float* const d = channels [destChannel] + destStartSample;
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, source, gain, numSamples);
if (isClear)
{
isClear = false;
if (gain != 1.0f)
FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples);
else
FloatVectorOperations::copy (d, source, numSamples);
}
else
FloatVectorOperations::add (d, source, numSamples);
{
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, source, gain, numSamples);
else
FloatVectorOperations::add (d, source, numSamples);
}
}
}
@@ -369,6 +452,7 @@ void AudioSampleBuffer::addFromWithRamp (const int destChannel,
{
if (numSamples > 0 && (startGain != 0.0f || endGain != 0.0f))
{
isClear = false;
const float increment = (endGain - startGain) / numSamples;
float* d = channels [destChannel] + destStartSample;
@@ -395,9 +479,20 @@ void AudioSampleBuffer::copyFrom (const int destChannel,
jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size);
if (numSamples > 0)
FloatVectorOperations::copy (channels [destChannel] + destStartSample,
source.channels [sourceChannel] + sourceStartSample,
numSamples);
{
if (source.isClear)
{
if (! isClear)
FloatVectorOperations::clear (channels [destChannel] + destStartSample, numSamples);
}
else
{
isClear = false;
FloatVectorOperations::copy (channels [destChannel] + destStartSample,
source.channels [sourceChannel] + sourceStartSample,
numSamples);
}
}
}
void AudioSampleBuffer::copyFrom (const int destChannel,
@@ -410,7 +505,10 @@ void AudioSampleBuffer::copyFrom (const int destChannel,
jassert (source != nullptr);
if (numSamples > 0)
{
isClear = false;
FloatVectorOperations::copy (channels [destChannel] + destStartSample, source, numSamples);
}
}
void AudioSampleBuffer::copyFrom (const int destChannel,
@@ -425,17 +523,24 @@ void AudioSampleBuffer::copyFrom (const int destChannel,
if (numSamples > 0)
{
float* d = channels [destChannel] + destStartSample;
float* const d = channels [destChannel] + destStartSample;
if (gain != 1.0f)
{
if (gain == 0)
FloatVectorOperations::clear (d, numSamples);
{
if (! isClear)
FloatVectorOperations::clear (d, numSamples);
}
else
{
isClear = false;
FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples);
}
}
else
{
isClear = false;
FloatVectorOperations::copy (d, source, numSamples);
}
}
@@ -460,6 +565,7 @@ void AudioSampleBuffer::copyFromWithRamp (const int destChannel,
{
if (numSamples > 0 && (startGain != 0.0f || endGain != 0.0f))
{
isClear = false;
const float increment = (endGain - startGain) / numSamples;
float* d = channels [destChannel] + destStartSample;
@@ -477,8 +583,9 @@ void AudioSampleBuffer::reverse (int channel, int startSample, int numSamples) c
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
std::reverse (channels[channel] + startSample,
channels[channel] + startSample + numSamples);
if (! isClear)
std::reverse (channels[channel] + startSample,
channels[channel] + startSample + numSamples);
}
void AudioSampleBuffer::reverse (int startSample, int numSamples) const noexcept
@@ -487,17 +594,17 @@ void AudioSampleBuffer::reverse (int startSample, int numSamples) const noexcept
reverse (i, startSample, numSamples);
}
void AudioSampleBuffer::findMinMax (const int channel,
const int startSample,
int numSamples,
float& minVal,
float& maxVal) const noexcept
Range<float> AudioSampleBuffer::findMinMax (const int channel,
const int startSample,
int numSamples) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
FloatVectorOperations::findMinAndMax (channels [channel] + startSample,
numSamples, minVal, maxVal);
if (isClear)
return Range<float>();
return FloatVectorOperations::findMinAndMax (channels [channel] + startSample, numSamples);
}
float AudioSampleBuffer::getMagnitude (const int channel,
@@ -507,18 +614,21 @@ float AudioSampleBuffer::getMagnitude (const int channel,
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
float mn, mx;
findMinMax (channel, startSample, numSamples, mn, mx);
if (isClear)
return 0.0f;
const Range<float> r (findMinMax (channel, startSample, numSamples));
return jmax (mn, -mn, mx, -mx);
return jmax (r.getStart(), -r.getStart(), r.getEnd(), -r.getEnd());
}
float AudioSampleBuffer::getMagnitude (int startSample, int numSamples) const noexcept
{
float mag = 0.0f;
for (int i = 0; i < numChannels; ++i)
mag = jmax (mag, getMagnitude (i, startSample, numSamples));
if (! isClear)
for (int i = 0; i < numChannels; ++i)
mag = jmax (mag, getMagnitude (i, startSample, numSamples));
return mag;
}
@@ -530,7 +640,7 @@ float AudioSampleBuffer::getRMSLevel (const int channel,
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (numSamples <= 0 || channel < 0 || channel >= numChannels)
if (numSamples <= 0 || channel < 0 || channel >= numChannels || isClear)
return 0.0f;
const float* const data = channels [channel] + startSample;


+ 97
- 19
source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h View File

@@ -116,27 +116,58 @@ public:
*/
int getNumSamples() const noexcept { return size; }
/** Returns a pointer one of the buffer's channels.
/** Returns a pointer to an array of read-only samples in one of the buffer's channels.
For speed, this doesn't check whether the channel number is out of range,
so be careful when using it!
If you need to write to the data, do NOT call this method and const_cast the
result! Instead, you must call getWritePointer so that the buffer knows you're
planning on modifying the data.
*/
float* getSampleData (const int channelNumber) const noexcept
const float* getReadPointer (int channelNumber) const noexcept
{
jassert (isPositiveAndBelow (channelNumber, numChannels));
return channels [channelNumber];
}
/** Returns a pointer to a sample in one of the buffer's channels.
/** Returns a pointer to an array of read-only samples in one of the buffer's channels.
For speed, this doesn't check whether the channel number or index are out of range,
so be careful when using it!
If you need to write to the data, do NOT call this method and const_cast the
result! Instead, you must call getWritePointer so that the buffer knows you're
planning on modifying the data.
*/
const float* getReadPointer (int channelNumber, int sampleIndex) const noexcept
{
jassert (isPositiveAndBelow (channelNumber, numChannels));
jassert (isPositiveAndBelow (sampleIndex, size));
return channels [channelNumber] + sampleIndex;
}
For speed, this doesn't check whether the channel and sample number
are out-of-range, so be careful when using it!
/** Returns a writeable pointer to one of the buffer's channels.
For speed, this doesn't check whether the channel number is out of range,
so be careful when using it!
Note that if you're not planning on writing to the data, you should always
use getReadPointer instead.
*/
float* getSampleData (const int channelNumber,
const int sampleOffset) const noexcept
float* getWritePointer (int channelNumber) noexcept
{
jassert (isPositiveAndBelow (channelNumber, numChannels));
jassert (isPositiveAndBelow (sampleOffset, size));
return channels [channelNumber] + sampleOffset;
isClear = false;
return channels [channelNumber];
}
/** Returns a writeable pointer to one of the buffer's channels.
For speed, this doesn't check whether the channel number or index are out of range,
so be careful when using it!
Note that if you're not planning on writing to the data, you should
use getReadPointer instead.
*/
float* getWritePointer (int channelNumber, int sampleIndex) noexcept
{
jassert (isPositiveAndBelow (channelNumber, numChannels));
jassert (isPositiveAndBelow (sampleIndex, size));
isClear = false;
return channels [channelNumber] + sampleIndex;
}
/** Returns an array of pointers to the channels in the buffer.
@@ -144,7 +175,14 @@ public:
Don't modify any of the pointers that are returned, and bear in mind that
these will become invalid if the buffer is resized.
*/
float** getArrayOfChannels() const noexcept { return channels; }
const float** getArrayOfReadPointers() const noexcept { return const_cast<const float**> (channels); }
/** Returns an array of pointers to the channels in the buffer.
Don't modify any of the pointers that are returned, and bear in mind that
these will become invalid if the buffer is resized.
*/
float** getArrayOfWritePointers() noexcept { isClear = false; return channels; }
//==============================================================================
/** Changes the buffer's size or number of channels.
@@ -216,6 +254,36 @@ public:
int startSample,
int numSamples) noexcept;
/** Returns true if the buffer has been entirely cleared.
Note that this does not actually measure the contents of the buffer - it simply
returns a flag that is set when the buffer is cleared, and which is reset whenever
functions like getWritePointer() are invoked. That means the method does not take
any time, but it may return false negatives when in fact the buffer is still empty.
*/
bool hasBeenCleared() const noexcept { return isClear; }
//==============================================================================
/** Returns a sample from the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
float getSample (int channel, int sampleIndex) const noexcept;
/** Sets a sample in the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void setSample (int destChannel, int destSample, float newValue) noexcept;
/** Adds a value to a sample in the buffer.
The channel and index are not checked - they are expected to be in-range. If not,
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void addSample (int destChannel, int destSample, float valueToAdd) noexcept;
/** Applies a gain multiple to a region of one channel.
For speed, this doesn't check whether the channel and sample number
@@ -392,19 +460,15 @@ public:
float endGain) noexcept;
/** Finds the highest and lowest sample values in a given range.
/** Returns a Range indicating the lowest and highest sample values in a given section.
@param channel the channel to read from
@param startSample the start sample within the channel
@param numSamples the number of samples to check
@param minVal on return, the lowest value that was found
@param maxVal on return, the highest value that was found
*/
void findMinMax (int channel,
int startSample,
int numSamples,
float& minVal,
float& maxVal) const noexcept;
Range<float> findMinMax (int channel,
int startSample,
int numSamples) const noexcept;
/** Finds the highest absolute sample value within a region of a channel. */
float getMagnitude (int channel,
@@ -426,13 +490,27 @@ public:
/** Reverses a part of the buffer. */
void reverse (int startSample, int numSamples) const noexcept;
//==============================================================================
#ifndef DOXYGEN
// Note that these methods have now been replaced by getReadPointer() and getWritePointer()
JUCE_DEPRECATED (const float* getSampleData (int channel) const) { return getReadPointer (channel); }
JUCE_DEPRECATED (const float* getSampleData (int channel, int index) const) { return getReadPointer (channel, index); }
JUCE_DEPRECATED (float* getSampleData (int channel)) { return getWritePointer (channel); }
JUCE_DEPRECATED (float* getSampleData (int channel, int index)) { return getWritePointer (channel, index); }
// These have been replaced by getArrayOfReadPointers() and getArrayOfWritePointers()
JUCE_DEPRECATED (const float** getArrayOfChannels() const) { return getArrayOfReadPointers(); }
JUCE_DEPRECATED (float** getArrayOfChannels()) { return getArrayOfWritePointers(); }
#endif
private:
//==============================================================================
int numChannels, size;
size_t allocatedBytes;
float** channels;
HeapBlock <char, true> allocatedData;
HeapBlock<char, true> allocatedData;
float* preallocatedChannelSpace [32];
bool isClear;
void allocateData();
void allocateChannels (float* const* dataToReferTo, int offset);


+ 506
- 363
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
File diff suppressed because it is too large
View File


+ 44
- 2
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -38,48 +38,90 @@ public:
/** Clears a vector of floats. */
static void JUCE_CALLTYPE clear (float* dest, int numValues) noexcept;
/** Clears a vector of doubles. */
static void JUCE_CALLTYPE clear (double* dest, int numValues) noexcept;
/** Copies a repeated value into a vector of floats. */
static void JUCE_CALLTYPE fill (float* dest, float valueToFill, int numValues) noexcept;
/** Copies a repeated value into a vector of doubles. */
static void JUCE_CALLTYPE fill (double* dest, double valueToFill, int numValues) noexcept;
/** Copies a vector of floats. */
static void JUCE_CALLTYPE copy (float* dest, const float* src, int numValues) noexcept;
/** Copies a vector of doubles. */
static void JUCE_CALLTYPE copy (double* dest, const double* src, int numValues) noexcept;
/** Copies a vector of floats, multiplying each value by a given multiplier */
static void JUCE_CALLTYPE copyWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
/** Copies a vector of doubles, multiplying each value by a given multiplier */
static void JUCE_CALLTYPE copyWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
/** Adds a fixed value to the destination values. */
static void JUCE_CALLTYPE add (float* dest, float amountToAdd, int numValues) noexcept;
/** Adds a fixed value to the destination values. */
static void JUCE_CALLTYPE add (float* dest, float amount, int numValues) noexcept;
static void JUCE_CALLTYPE add (double* dest, double amountToAdd, int numValues) noexcept;
/** Adds the source values to the destination values. */
static void JUCE_CALLTYPE add (float* dest, const float* src, int numValues) noexcept;
/** Adds the source values to the destination values. */
static void JUCE_CALLTYPE add (double* dest, const double* src, int numValues) noexcept;
/** Subtracts the source values from the destination values. */
static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) noexcept;
/** Subtracts the source values from the destination values. */
static void JUCE_CALLTYPE subtract (double* dest, const double* src, int numValues) noexcept;
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (double* dest, const double* src, double multiplier, int numValues) noexcept;
/** Multiplies the destination values by the source values. */
static void JUCE_CALLTYPE multiply (float* dest, const float* src, int numValues) noexcept;
/** Multiplies the destination values by the source values. */
static void JUCE_CALLTYPE multiply (double* dest, const double* src, int numValues) noexcept;
/** Multiplies each of the destination values by a fixed multiplier. */
static void JUCE_CALLTYPE multiply (float* dest, float multiplier, int numValues) noexcept;
/** Multiplies each of the destination values by a fixed multiplier. */
static void JUCE_CALLTYPE multiply (double* dest, double multiplier, int numValues) noexcept;
/** Copies a source vector to a destination, negating each value. */
static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept;
/** Copies a source vector to a destination, negating each value. */
static void JUCE_CALLTYPE negate (double* dest, const double* src, int numValues) noexcept;
/** Converts a stream of integers to floats, multiplying each one by the given multiplier. */
static void JUCE_CALLTYPE convertFixedToFloat (float* dest, const int* src, float multiplier, int numValues) noexcept;
/** Finds the miniumum and maximum values in the given array. */
static void JUCE_CALLTYPE findMinAndMax (const float* src, int numValues, float& minResult, float& maxResult) noexcept;
static Range<float> JUCE_CALLTYPE findMinAndMax (const float* src, int numValues) noexcept;
/** Finds the miniumum and maximum values in the given array. */
static Range<double> JUCE_CALLTYPE findMinAndMax (const double* src, int numValues) noexcept;
/** Finds the miniumum value in the given array. */
static float JUCE_CALLTYPE findMinimum (const float* src, int numValues) noexcept;
/** Finds the miniumum value in the given array. */
static double JUCE_CALLTYPE findMinimum (const double* src, int numValues) noexcept;
/** Finds the maximum value in the given array. */
static float JUCE_CALLTYPE findMaximum (const float* src, int numValues) noexcept;
/** Finds the maximum value in the given array. */
static double JUCE_CALLTYPE findMaximum (const double* src, int numValues) noexcept;
/** On Intel CPUs, this method enables or disables the SSE flush-to-zero mode.
Effectively, this is a wrapper around a call to _MM_SET_FLUSH_ZERO_MODE
*/


+ 4
- 0
source/modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -36,6 +36,10 @@
#include "AppConfig.h"
#include "juce_audio_basics.h"
#if JUCE_MINGW && ! defined (__SSE2__)
#define JUCE_USE_SSE_INTRINSICS 0
#endif
#ifndef JUCE_USE_SSE_INTRINSICS
#define JUCE_USE_SSE_INTRINSICS 1
#endif


+ 4
- 2
source/modules/juce_audio_basics/midi/juce_MidiFile.cpp View File

@@ -350,11 +350,13 @@ void MidiFile::convertTimestampTicksToSeconds()
}
//==============================================================================
bool MidiFile::writeTo (OutputStream& out)
bool MidiFile::writeTo (OutputStream& out, int midiFileType)
{
jassert (midiFileType >= 0 && midiFileType <= 2);
out.writeIntBigEndian ((int) ByteOrder::bigEndianInt ("MThd"));
out.writeIntBigEndian (6);
out.writeShortBigEndian (1); // type
out.writeShortBigEndian ((short) midiFileType);
out.writeShortBigEndian ((short) tracks.size());
out.writeShortBigEndian (timeFormat);


+ 3
- 1
source/modules/juce_audio_basics/midi/juce_MidiFile.h View File

@@ -151,9 +151,11 @@ public:
bool readFrom (InputStream& sourceStream);
/** Writes the midi tracks as a standard midi file.
The midiFileType value is written as the file's format type, which can be 0, 1
or 2 - see the midi file spec for more info about that.
@returns true if the operation succeeded.
*/
bool writeTo (OutputStream& destStream);
bool writeTo (OutputStream& destStream, int midiFileType = 1);
/** Converts the timestamp of all the midi events from midi ticks to seconds.


+ 3
- 2
source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp View File

@@ -152,7 +152,8 @@ MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
}
}
MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte, double t)
MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte,
double t, bool sysexHasEmbeddedLength)
: timeStamp (t)
{
const uint8* src = static_cast<const uint8*> (srcData);
@@ -175,7 +176,7 @@ MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const
if (byte == 0xf0)
{
const uint8* d = src;
bool haveReadAllLengthBytes = false;
bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
int numVariableLengthSysexBytes = 0;
while (d < src + sz)


+ 9
- 5
source/modules/juce_audio_basics/midi/juce_MidiMessage.h View File

@@ -82,10 +82,14 @@ public:
has in fact been dropped.
@param timeStamp the time to give the midi message - this value doesn't
use any particular units, so will be application-specific
@param sysexHasEmbeddedLength when reading sysexes, this flag indicates whether
to expect the data to begin with a variable-length field
indicating its size
*/
MidiMessage (const void* data, int maxBytesToUse,
int& numBytesUsed, uint8 lastStatusByte,
double timeStamp = 0);
double timeStamp = 0,
bool sysexHasEmbeddedLength = true);
/** Creates an active-sense message.
Since the MidiMessage has to contain a valid message, this default constructor
@@ -94,10 +98,10 @@ public:
MidiMessage() noexcept;
/** Creates a copy of another midi message. */
MidiMessage (const MidiMessage& other);
MidiMessage (const MidiMessage&);
/** Creates a copy of another midi message, with a different timestamp. */
MidiMessage (const MidiMessage& other, double newTimeStamp);
MidiMessage (const MidiMessage&, double newTimeStamp);
/** Destructor. */
~MidiMessage();
@@ -106,8 +110,8 @@ public:
MidiMessage& operator= (const MidiMessage& other);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
MidiMessage (MidiMessage&& other) noexcept;
MidiMessage& operator= (MidiMessage&& other) noexcept;
MidiMessage (MidiMessage&&) noexcept;
MidiMessage& operator= (MidiMessage&&) noexcept;
#endif
//==============================================================================


+ 1
- 1
source/modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.cpp View File

@@ -72,6 +72,6 @@ void IIRFilterAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& buff
for (int i = 0; i < numChannels; ++i)
iirFilters.getUnchecked(i)
->processSamples (bufferToFill.buffer->getSampleData (i, bufferToFill.startSample),
->processSamples (bufferToFill.buffer->getWritePointer (i, bufferToFill.startSample),
bufferToFill.numSamples);
}

+ 5
- 5
source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp View File

@@ -121,7 +121,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
// for down-sampling, pre-apply the filter..
for (int i = channelsToProcess; --i >= 0;)
applyFilter (buffer.getSampleData (i, endOfBufferPos), numToDo, filterStates[i]);
applyFilter (buffer.getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]);
}
sampsInBuffer += numToDo;
@@ -130,8 +130,8 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
for (int channel = 0; channel < channelsToProcess; ++channel)
{
destBuffers[channel] = info.buffer->getSampleData (channel, info.startSample);
srcBuffers[channel] = buffer.getSampleData (channel, 0);
destBuffers[channel] = info.buffer->getWritePointer (channel, info.startSample);
srcBuffers[channel] = buffer.getReadPointer (channel);
}
int nextPos = (bufferPos + 1) % bufferSize;
@@ -163,14 +163,14 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf
{
// for up-sampling, apply the filter after transposing..
for (int i = channelsToProcess; --i >= 0;)
applyFilter (info.buffer->getSampleData (i, info.startSample), info.numSamples, filterStates[i]);
applyFilter (info.buffer->getWritePointer (i, info.startSample), info.numSamples, filterStates[i]);
}
else if (localRatio <= 1.0001 && info.numSamples > 0)
{
// if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
for (int i = channelsToProcess; --i >= 0;)
{
const float* const endOfBuffer = info.buffer->getSampleData (i, info.startSample + info.numSamples - 1);
const float* const endOfBuffer = info.buffer->getReadPointer (i, info.startSample + info.numSamples - 1);
FilterState& fs = filterStates[i];
if (info.numSamples > 1)


+ 2
- 1
source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h View File

@@ -81,7 +81,8 @@ private:
double coefficients[6];
SpinLock ratioLock;
const int numChannels;
HeapBlock<float*> destBuffers, srcBuffers;
HeapBlock<float*> destBuffers;
HeapBlock<const float*> srcBuffers;
void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6);
void createLowPass (double proportionalRate);


+ 2
- 2
source/modules/juce_audio_basics/sources/juce_ReverbAudioSource.cpp View File

@@ -48,12 +48,12 @@ void ReverbAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& bufferT
if (! bypass)
{
float* const firstChannel = bufferToFill.buffer->getSampleData (0, bufferToFill.startSample);
float* const firstChannel = bufferToFill.buffer->getWritePointer (0, bufferToFill.startSample);
if (bufferToFill.buffer->getNumChannels() > 1)
{
reverb.processStereo (firstChannel,
bufferToFill.buffer->getSampleData (1, bufferToFill.startSample),
bufferToFill.buffer->getWritePointer (1, bufferToFill.startSample),
bufferToFill.numSamples);
}
else


+ 1
- 1
source/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp View File

@@ -70,6 +70,6 @@ void ToneGeneratorAudioSource::getNextAudioBlock (const AudioSourceChannelInfo&
currentPhase += phasePerSample;
for (int j = info.buffer->getNumChannels(); --j >= 0;)
*info.buffer->getSampleData (j, info.startSample + i) = sample;
info.buffer->setSample (j, info.startSample + i, sample);
}
}

+ 23
- 16
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -58,6 +58,11 @@ void SynthesiserVoice::clearCurrentNote()
void SynthesiserVoice::aftertouchChanged (int) {}
bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const noexcept
{
return noteOnTime < other.noteOnTime;
}
//==============================================================================
Synthesiser::Synthesiser()
: sampleRate (0),
@@ -407,12 +412,11 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
}
//==============================================================================
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
const bool stealIfNoneAvailable) const
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const
{
const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
for (int i = 0; i < voices.size(); ++i)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
@@ -421,22 +425,25 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
}
if (stealIfNoneAvailable)
{
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
SynthesiserVoice* oldest = nullptr;
return findVoiceToSteal (soundToPlay);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
return nullptr;
}
if (voice->canPlaySound (soundToPlay)
&& (oldest == nullptr || oldest->noteOnTime > voice->noteOnTime))
oldest = voice;
}
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const
{
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
SynthesiserVoice* oldest = nullptr;
jassert (oldest != nullptr);
return oldest;
for (int i = 0; i < voices.size(); ++i)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->canPlaySound (soundToPlay)
&& (oldest == nullptr || voice->wasStartedBefore (*oldest)))
oldest = voice;
}
return nullptr;
jassert (oldest != nullptr);
return oldest;
}

+ 9
- 0
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -199,6 +199,9 @@ public:
/** Returns true if the sostenuto pedal is currently active for this voice. */
bool isSostenutoPedalDown() const noexcept { return sostenutoPedalDown; }
/** Returns true if this voice started playing its current note before the other voice did. */
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
protected:
//==============================================================================
/** Returns the current target sample rate at which rendering is being done.
@@ -481,6 +484,12 @@ protected:
virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay,
const bool stealIfNoneAvailable) const;
/** Chooses a voice that is most suitable for being re-used.
The default method returns the one that has been playing for the longest, but
you may want to override this and do something more cunning instead.
*/
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay) const;
/** Starts a specified voice playing a particular sound.
You'll probably never need to call this, it's used internally by noteOn(), but


+ 5
- 6
source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -728,7 +728,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples);
float** const tempChans = tempBuffer.getArrayOfChannels();
float** const tempChans = tempBuffer.getArrayOfWritePointers();
for (int i = callbacks.size(); --i > 0;)
{
@@ -757,7 +757,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
if (testSound != nullptr)
{
const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
const float* const src = testSound->getSampleData (0, testSoundPosition);
const float* const src = testSound->getReadPointer (0, testSoundPosition);
for (int i = 0; i < numOutputChannels; ++i)
for (int j = 0; j < numSamps; ++j)
@@ -951,16 +951,15 @@ void AudioDeviceManager::playTestSound()
const double sampleRate = currentAudioDevice->getCurrentSampleRate();
const int soundLength = (int) sampleRate;
AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength);
float* samples = newSound->getSampleData (0);
const double frequency = 440.0;
const float amplitude = 0.5f;
const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency);
AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength);
for (int i = 0; i < soundLength; ++i)
samples[i] = amplitude * (float) std::sin (i * phasePerSample);
newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample));
newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);


+ 4
- 4
source/modules/juce_audio_devices/native/juce_android_Audio.cpp View File

@@ -304,7 +304,7 @@ public:
for (int chan = 0; chan < inputChannelBuffer.getNumChannels(); ++chan)
{
AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> d (inputChannelBuffer.getSampleData (chan));
AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> d (inputChannelBuffer.getWritePointer (chan));
if (chan < numDeviceInputChannels)
{
@@ -328,8 +328,8 @@ public:
if (callback != nullptr)
{
callback->audioDeviceIOCallback ((const float**) inputChannelBuffer.getArrayOfChannels(), numClientInputChannels,
outputChannelBuffer.getArrayOfChannels(), numClientOutputChannels,
callback->audioDeviceIOCallback (inputChannelBuffer.getArrayOfReadPointers(), numClientInputChannels,
outputChannelBuffer.getArrayOfWritePointers(), numClientOutputChannels,
actualBufferSize);
}
else
@@ -349,7 +349,7 @@ public:
{
AudioData::Pointer <AudioData::Int16, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst> d (dest + chan, numDeviceOutputChannels);
const float* const sourceChanData = outputChannelBuffer.getSampleData (jmin (chan, outputChannelBuffer.getNumChannels() - 1));
const float* const sourceChanData = outputChannelBuffer.getReadPointer (jmin (chan, outputChannelBuffer.getNumChannels() - 1));
AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> s (sourceChanData);
d.convertSamples (s, actualBufferSize);
}


+ 4
- 6
source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp View File

@@ -179,10 +179,8 @@ public:
if (callback != nullptr)
{
callback->audioDeviceIOCallback (numInputChannels > 0 ? (const float**) inputBuffer.getArrayOfChannels() : nullptr,
numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfChannels() : nullptr,
numOutputChannels,
callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
actualBufferSize);
}
else
@@ -404,7 +402,7 @@ private:
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
DstSampleType dstData (destBuffer + i, bufferList.numChannels);
SrcSampleType srcData (buffer.getSampleData (i, offset));
SrcSampleType srcData (buffer.getReadPointer (i, offset));
dstData.convertSamples (srcData, bufferList.numSamples);
}
@@ -522,7 +520,7 @@ private:
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
DstSampleType dstData (buffer.getSampleData (i, offset));
DstSampleType dstData (buffer.getWritePointer (i, offset));
SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
dstData.convertSamples (srcData, bufferList.numSamples);
}


+ 2
- 2
source/modules/juce_audio_devices/native/juce_ios_Audio.cpp View File

@@ -227,10 +227,10 @@ private:
zeromem (outputChannels, sizeof (outputChannels));
for (int i = 0; i < numInputChannels; ++i)
inputChannels[i] = floatData.getSampleData (i);
inputChannels[i] = floatData.getWritePointer (i);
for (int i = 0; i < numOutputChannels; ++i)
outputChannels[i] = floatData.getSampleData (i + numInputChannels);
outputChannels[i] = floatData.getWritePointer (i + numInputChannels);
}
}


+ 7
- 6
source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp View File

@@ -311,7 +311,7 @@ public:
bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
{
jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
float** const data = outputChannelBuffer.getArrayOfChannels();
float* const* const data = outputChannelBuffer.getArrayOfWritePointers();
snd_pcm_sframes_t numDone = 0;
if (isInterleaved)
@@ -343,7 +343,7 @@ public:
bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
{
jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
float** const data = inputChannelBuffer.getArrayOfChannels();
float* const* const data = inputChannelBuffer.getArrayOfWritePointers();
if (isInterleaved)
{
@@ -497,7 +497,7 @@ public:
{
if (inputChannels[i])
{
inputChannelDataForCallback.add (inputChannelBuffer.getSampleData (i));
inputChannelDataForCallback.add (inputChannelBuffer.getReadPointer (i));
currentInputChans.setBit (i);
}
}
@@ -516,7 +516,7 @@ public:
{
if (outputChannels[i])
{
outputChannelDataForCallback.add (outputChannelBuffer.getSampleData (i));
outputChannelDataForCallback.add (outputChannelBuffer.getWritePointer (i));
currentOutputChans.setBit (i);
}
}
@@ -666,7 +666,7 @@ public:
if (callback != nullptr)
{
callback->audioDeviceIOCallback ((const float**) inputChannelDataForCallback.getRawDataPointer(),
callback->audioDeviceIOCallback (inputChannelDataForCallback.getRawDataPointer(),
inputChannelDataForCallback.size(),
outputChannelDataForCallback.getRawDataPointer(),
outputChannelDataForCallback.size(),
@@ -736,7 +736,8 @@ private:
CriticalSection callbackLock;
AudioSampleBuffer inputChannelBuffer, outputChannelBuffer;
Array<float*> inputChannelDataForCallback, outputChannelDataForCallback;
Array<const float*> inputChannelDataForCallback;
Array<float*> outputChannelDataForCallback;
unsigned int minChansOut, maxChansOut;
unsigned int minChansIn, maxChansIn;


+ 2
- 2
source/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm View File

@@ -129,9 +129,9 @@ private:
typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
left.convertSamples (SourceSampleFormat (tempBuffer.getReadPointer (0)), numSamples);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
right.convertSamples (SourceSampleFormat (tempBuffer.getReadPointer (1)), numSamples);
source->readPosition += numSamples;
}


+ 10
- 9
source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp View File

@@ -1319,14 +1319,15 @@ private:
AudioSampleBuffer buffer (fifos.getNumChannels(), numSamples);
buffer.clear();
Array<float*> inputChans, outputChans;
Array<const float*> inputChans;
Array<float*> outputChans;
for (int i = 0; i < devices.size(); ++i)
{
DeviceWrapper& d = *devices.getUnchecked(i);
for (int j = 0; j < d.numInputChans; ++j) inputChans.add (buffer.getSampleData (d.inputIndex + j));
for (int j = 0; j < d.numOutputChans; ++j) outputChans.add (buffer.getSampleData (d.outputIndex + j));
for (int j = 0; j < d.numInputChans; ++j) inputChans.add (buffer.getReadPointer (d.inputIndex + j));
for (int j = 0; j < d.numOutputChans; ++j) outputChans.add (buffer.getWritePointer (d.outputIndex + j));
}
const int numInputChans = inputChans.size();
@@ -1535,8 +1536,8 @@ private:
for (int i = 0; i < numInputChans; ++i)
{
const int index = inputIndex + i;
float* const dest = destBuffer.getSampleData (index);
const float* const src = owner.fifos.getSampleData (index);
float* const dest = destBuffer.getWritePointer (index);
const float* const src = owner.fifos.getReadPointer (index);
if (size1 > 0) FloatVectorOperations::copy (dest, src + start1, size1);
if (size2 > 0) FloatVectorOperations::copy (dest + size1, src + start2, size2);
@@ -1561,8 +1562,8 @@ private:
for (int i = 0; i < numOutputChans; ++i)
{
const int index = outputIndex + i;
float* const dest = owner.fifos.getSampleData (index);
const float* const src = srcBuffer.getSampleData (index);
float* const dest = owner.fifos.getWritePointer (index);
const float* const src = srcBuffer.getReadPointer (index);
if (size1 > 0) FloatVectorOperations::copy (dest + start1, src, size1);
if (size2 > 0) FloatVectorOperations::copy (dest + start2, src + size1, size2);
@@ -1590,7 +1591,7 @@ private:
for (int i = 0; i < numInputChannels; ++i)
{
float* const dest = buf.getSampleData (inputIndex + i);
float* const dest = buf.getWritePointer (inputIndex + i);
const float* const src = inputChannelData[i];
if (size1 > 0) FloatVectorOperations::copy (dest + start1, src, size1);
@@ -1622,7 +1623,7 @@ private:
for (int i = 0; i < numOutputChannels; ++i)
{
float* const dest = outputChannelData[i];
const float* const src = buf.getSampleData (outputIndex + i);
const float* const src = buf.getReadPointer (outputIndex + i);
if (size1 > 0) FloatVectorOperations::copy (dest, src + start1, size1);
if (size2 > 0) FloatVectorOperations::copy (dest + size1, src + start2, size2);


+ 2
- 2
source/modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp View File

@@ -391,9 +391,9 @@ bool AudioCDBurner::addAudioTrack (AudioSource* audioSource, int numSamples)
AudioData::NonInterleaved, AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (0)), samplesPerBlock);
left.convertSamples (SourceSampleFormat (sourceBuffer.getReadPointer (0)), samplesPerBlock);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (sourceBuffer.getSampleData (1)), samplesPerBlock);
right.convertSamples (SourceSampleFormat (sourceBuffer.getReadPointer (1)), samplesPerBlock);
hr = pimpl->redbook->AddAudioTrackBlocks (buffer, bytesPerBlock);


+ 6
- 18
source/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp View File

@@ -998,10 +998,8 @@ public:
if (isStarted)
{
callback->audioDeviceIOCallback (const_cast <const float**> (inputBuffers.getArrayOfChannels()),
inputBuffers.getNumChannels(),
outputBuffers.getArrayOfChannels(),
outputBuffers.getNumChannels(),
callback->audioDeviceIOCallback (inputBuffers.getArrayOfReadPointers(), inputBuffers.getNumChannels(),
outputBuffers.getArrayOfWritePointers(), outputBuffers.getNumChannels(),
bufferSizeSamples);
}
else
@@ -1105,13 +1103,8 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels,
for (int i = 0; i <= enabledInputs.getHighestBit(); i += 2)
{
float* left = nullptr;
if (enabledInputs[i])
left = inputBuffers.getSampleData (numIns++);
float* right = nullptr;
if (enabledInputs[i + 1])
right = inputBuffers.getSampleData (numIns++);
float* left = enabledInputs[i] ? inputBuffers.getWritePointer (numIns++) : nullptr;
float* right = enabledInputs[i + 1] ? inputBuffers.getWritePointer (numIns++) : nullptr;
if (left != nullptr || right != nullptr)
inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [inputDeviceIndex],
@@ -1131,13 +1124,8 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels,
for (int i = 0; i <= enabledOutputs.getHighestBit(); i += 2)
{
float* left = nullptr;
if (enabledOutputs[i])
left = outputBuffers.getSampleData (numOuts++);
float* right = nullptr;
if (enabledOutputs[i + 1])
right = outputBuffers.getSampleData (numOuts++);
float* left = enabledOutputs[i] ? outputBuffers.getWritePointer (numOuts++) : nullptr;
float* right = enabledOutputs[i + 1] ? outputBuffers.getWritePointer (numOuts++) : nullptr;
if (left != nullptr || right != nullptr)
outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[outputDeviceIndex],


+ 3
- 3
source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp View File

@@ -632,7 +632,7 @@ public:
{
closeClient();
captureClient = nullptr;
reservoir.setSize (0);
reservoir.reset();
}
template <class SourceType>
@@ -1063,8 +1063,8 @@ public:
AudioSampleBuffer ins (jmax (1, numInputBuffers), bufferSize + 32);
AudioSampleBuffer outs (jmax (1, numOutputBuffers), bufferSize + 32);
float** const inputBuffers = ins.getArrayOfChannels();
float** const outputBuffers = outs.getArrayOfChannels();
float** const inputBuffers = ins.getArrayOfWritePointers();
float** const outputBuffers = outs.getArrayOfWritePointers();
ins.clear();
while (! threadShouldExit())


+ 1
- 1
source/modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp View File

@@ -115,7 +115,7 @@ void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData,
for (int i = numOutputs; i < numInputs; ++i)
{
channels[numActiveChans] = tempBuffer.getSampleData (i - numOutputs, 0);
channels[numActiveChans] = tempBuffer.getWritePointer (i - numOutputs);
memcpy (channels[numActiveChans], inputChans[i], sizeof (float) * (size_t) numSamples);
++numActiveChans;
}


+ 3
- 2
source/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp View File

@@ -61,6 +61,7 @@ namespace FlacNamespace
#define FLAC__HAS_X86INTRIN 1
#endif
#undef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#define flac_max jmax
#define flac_min jmin
@@ -175,7 +176,7 @@ public:
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
if (destSamples[i] != nullptr)
memcpy (destSamples[i] + startOffsetInDestBuffer,
reservoir.getSampleData (i, (int) (startSampleInFile - reservoirStart)),
reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)),
sizeof (int) * (size_t) num);
startOffsetInDestBuffer += num;
@@ -242,7 +243,7 @@ public:
if (src != nullptr)
{
int* const dest = reinterpret_cast<int*> (reservoir.getSampleData(i));
int* const dest = reinterpret_cast<int*> (reservoir.getWritePointer(i));
for (int j = 0; j < numSamples; ++j)
dest[j] = src[j] << bitsToShift;


+ 21
- 6
source/modules/juce_audio_formats/codecs/juce_MP3AudioFormat.cpp View File

@@ -516,12 +516,21 @@ struct MP3Frame
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } }
};
switch (layer)
if (bitrateIndex == 0)
{
case 1: frameSize = (((frameSizes[lsf][0][bitrateIndex] * 12000) / getFrequency() + padding) * 4) - 4; break;
case 2: frameSize = (frameSizes[lsf][1][bitrateIndex] * 144000) / getFrequency() + (padding - 4); break;
case 3: frameSize = (bitrateIndex == 0) ? 0 : ((frameSizes[lsf][2][bitrateIndex] * 144000) / (getFrequency() << lsf) + (padding - 4)); break;
default: break;
jassertfalse; // This means the file is using "free format". Apparently very few decoders
// support this mode, and this one certainly doesn't handle it correctly!
frameSize = 0;
}
else
{
switch (layer)
{
case 1: frameSize = (((frameSizes[lsf][0][bitrateIndex] * 12000) / getFrequency() + padding) * 4) - 4; break;
case 2: frameSize = (frameSizes[lsf][1][bitrateIndex] * 144000) / getFrequency() + (padding - 4); break;
case 3: frameSize = (bitrateIndex == 0) ? 0 : ((frameSizes[lsf][2][bitrateIndex] * 144000) / (getFrequency() << lsf) + (padding - 4)); break;
default: break;
}
}
}
@@ -1451,7 +1460,7 @@ struct MP3Stream
bufferPointer = bufferSpace[bufferSpaceIndex] + 512;
bitIndex = 0;
if (lastFrameSize == -1)
if (lastFrameSize < 0)
return 1;
}
@@ -1513,8 +1522,14 @@ struct MP3Stream
else
{
const int nextFrameOffset = scanForNextFrameHeader (true);
wasFreeFormat = isFreeFormat;
if (nextFrameOffset < 0)
{
lastFrameSize = frameSize;
return result;
}
frameSize = nextFrameOffset + sideInfoSize + dataSize;
lastFrameSizeNoPadding = frameSize - frame.padding;


+ 2
- 6
source/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp View File

@@ -173,7 +173,7 @@ public:
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
if (destSamples[i] != nullptr)
memcpy (destSamples[i] + startOffsetInDestBuffer,
reservoir.getSampleData (i, (int) (startSampleInFile - reservoirStart)),
reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)),
sizeof (float) * (size_t) numToUse);
startSampleInFile += numToUse;
@@ -210,11 +210,7 @@ public:
jassert (samps <= numToRead);
for (int i = jmin ((int) numChannels, reservoir.getNumChannels()); --i >= 0;)
{
memcpy (reservoir.getSampleData (i, offset),
dataIn[i],
sizeof (float) * (size_t) samps);
}
memcpy (reservoir.getWritePointer (i, offset), dataIn[i], sizeof (float) * (size_t) samps);
numToRead -= samps;
offset += samps;


+ 7
- 5
source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -983,11 +983,13 @@ private:
switch (numChannels)
{
case 1: return 0;
case 2: return 1 + 2; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
case 5: return 1 + 2 + 4 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 6: return 1 + 2 + 4 + 8 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 7: return 1 + 2 + 4 + 16 + 32 + 512 + 1024; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
case 8: return 1 + 2 + 4 + 8 + 16 + 32 + 512 + 1024; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
case 2: return 1 + 2; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
case 3: return 1 + 2 + 4; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER
case 4: return 1 + 2 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 5: return 1 + 2 + 4 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 6: return 1 + 2 + 4 + 8 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 7: return 1 + 2 + 4 + 16 + 32 + 512 + 1024; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
case 8: return 1 + 2 + 4 + 8 + 16 + 32 + 512 + 1024; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
default: break;
}


+ 1
- 0
source/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp View File

@@ -344,6 +344,7 @@ Array<int> WindowsMediaAudioFormat::getPossibleBitDepths() { return Array<i
bool WindowsMediaAudioFormat::canDoStereo() { return true; }
bool WindowsMediaAudioFormat::canDoMono() { return true; }
bool WindowsMediaAudioFormat::isCompressed() { return true; }
//==============================================================================
AudioFormatReader* WindowsMediaAudioFormat::createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails)


+ 1
- 0
source/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.h View File

@@ -40,6 +40,7 @@ public:
Array<int> getPossibleBitDepths() override;
bool canDoStereo() override;
bool canDoMono() override;
bool isCompressed() override;
//==============================================================================
AudioFormatReader* createReaderFor (InputStream*, bool deleteStreamIfOpeningFails) override;


+ 15
- 16
source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp View File

@@ -106,7 +106,7 @@ static void readChannels (AudioFormatReader& reader,
const int64 readerStartSample, const int numTargetChannels)
{
for (int j = 0; j < numTargetChannels; ++j)
chans[j] = reinterpret_cast<int*> (buffer->getSampleData (j, startSample));
chans[j] = reinterpret_cast<int*> (buffer->getWritePointer (j, startSample));
chans[numTargetChannels] = nullptr;
reader.read (chans, numTargetChannels, readerStartSample, numSamples, true);
@@ -128,8 +128,8 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
if (numTargetChannels <= 2)
{
int* const dest0 = reinterpret_cast<int*> (buffer->getSampleData (0, startSample));
int* const dest1 = reinterpret_cast<int*> (numTargetChannels > 1 ? buffer->getSampleData (1, startSample) : nullptr);
int* const dest0 = reinterpret_cast<int*> (buffer->getWritePointer (0, startSample));
int* const dest1 = reinterpret_cast<int*> (numTargetChannels > 1 ? buffer->getWritePointer (1, startSample) : nullptr);
int* chans[3];
if (useReaderLeftChan == useReaderRightChan)
@@ -168,36 +168,35 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
if (! usesFloatingPointData)
for (int j = 0; j < numTargetChannels; ++j)
if (float* const d = buffer->getSampleData (j, startSample))
if (float* const d = buffer->getWritePointer (j, startSample))
FloatVectorOperations::convertFixedToFloat (d, reinterpret_cast<const int*> (d), 1.0f / 0x7fffffff, numSamples);
}
}
template <typename SampleType>
static inline void getChannelMinAndMax (SampleType* channel, const int numSamples, SampleType& mn, SampleType& mx)
static Range<SampleType> getChannelMinAndMax (SampleType* channel, int numSamples) noexcept
{
findMinAndMax (channel, numSamples, mn, mx);
return Range<SampleType>::findMinAndMax (channel, numSamples);
}
static inline void getChannelMinAndMax (float* channel, const int numSamples, float& mn, float& mx)
static Range<float> getChannelMinAndMax (float* channel, int numSamples) noexcept
{
FloatVectorOperations::findMinAndMax (channel, numSamples, mn, mx);
return FloatVectorOperations::findMinAndMax (channel, numSamples);
}
template <typename SampleType>
static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples,
SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax)
{
SampleType bufMin, bufMax;
getChannelMinAndMax (channels[0], numSamples, bufMin, bufMax);
lmax = jmax (lmax, bufMax);
lmin = jmin (lmin, bufMin);
Range<SampleType> range (getChannelMinAndMax (channels[0], numSamples));
lmax = jmax (lmax, range.getEnd());
lmin = jmin (lmin, range.getStart());
if (numChannels > 1)
{
getChannelMinAndMax (channels[1], numSamples, bufMin, bufMax);
rmax = jmax (rmax, bufMax);
rmin = jmin (rmin, bufMin);
range = getChannelMinAndMax (channels[1], numSamples);
rmax = jmax (rmax, range.getEnd());
rmin = jmin (rmin, range.getStart());
}
else
{
@@ -222,7 +221,7 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize);
float** const floatBuffer = tempSampleBuffer.getArrayOfChannels();
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
if (usesFloatingPointData)


+ 3
- 3
source/modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp View File

@@ -68,7 +68,7 @@ bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader,
int* buffers [128] = { 0 };
for (int i = tempBuffer.getNumChannels(); --i >= 0;)
buffers[i] = reinterpret_cast<int*> (tempBuffer.getSampleData (i, 0));
buffers[i] = reinterpret_cast<int*> (tempBuffer.getWritePointer (i, 0));
if (numSamplesToRead < 0)
numSamplesToRead = reader.lengthInSamples;
@@ -170,13 +170,13 @@ bool AudioFormatWriter::writeFromAudioSampleBuffer (const AudioSampleBuffer& sou
jassert (startSample >= 0 && startSample + numSamples <= source.getNumSamples() && numSourceChannels > 0);
if (startSample == 0)
return writeFromFloatArrays (source.getArrayOfChannels(), numSourceChannels, numSamples);
return writeFromFloatArrays (source.getArrayOfReadPointers(), numSourceChannels, numSamples);
const float* chans [256];
jassert ((int) numChannels < numElementsInArray (chans));
for (int i = 0; i < numSourceChannels; ++i)
chans[i] = source.getSampleData (i, startSample);
chans[i] = source.getReadPointer (i, startSample);
chans[numSourceChannels] = nullptr;


+ 1
- 1
source/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp View File

@@ -77,7 +77,7 @@ bool BufferingAudioReader::readSamples (int** destSamples, int numDestChannels,
dest += startOffsetInDestBuffer;
if (j < (int) numChannels)
FloatVectorOperations::copy (dest, block->buffer.getSampleData (j, offset), numToDo);
FloatVectorOperations::copy (dest, block->buffer.getReadPointer (j, offset), numToDo);
else
FloatVectorOperations::clear (dest, numToDo);
}


+ 4
- 4
source/modules/juce_audio_formats/sampler/juce_Sampler.cpp View File

@@ -154,12 +154,12 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
{
if (const SamplerSound* const playingSound = static_cast <SamplerSound*> (getCurrentlyPlayingSound().get()))
{
const float* const inL = playingSound->data->getSampleData (0, 0);
const float* const inL = playingSound->data->getReadPointer (0);
const float* const inR = playingSound->data->getNumChannels() > 1
? playingSound->data->getSampleData (1, 0) : nullptr;
? playingSound->data->getReadPointer (1) : nullptr;
float* outL = outputBuffer.getSampleData (0, startSample);
float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getSampleData (1, startSample) : nullptr;
float* outL = outputBuffer.getWritePointer (0, startSample);
float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
while (--numSamples >= 0)
{


+ 2
- 2
source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -530,7 +530,7 @@ public:
{
abl->mBuffers[j].mNumberChannels = 1;
abl->mBuffers[j].mDataByteSize = sizeof (float) * numSamples;
abl->mBuffers[j].mData = buffer.getSampleData (i * numOutputBusChannels + j, 0);
abl->mBuffers[j].mData = buffer.getWritePointer (i * numOutputBusChannels + j);
}
}
@@ -1050,7 +1050,7 @@ private:
if (bufferChannel < currentBuffer->getNumChannels())
{
memcpy (ioData->mBuffers[i].mData,
currentBuffer->getSampleData (bufferChannel, 0),
currentBuffer->getReadPointer (bufferChannel),
sizeof (float) * inNumberFrames);
}
else


+ 3
- 3
source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp View File

@@ -294,13 +294,13 @@ public:
{
for (int i = 0; i < inputs.size(); ++i)
plugin->connect_port (handle, inputs[i],
i < buffer.getNumChannels() ? buffer.getSampleData (i) : nullptr);
i < buffer.getNumChannels() ? buffer.getWritePointer (i) : nullptr);
if (plugin->run != nullptr)
{
for (int i = 0; i < outputs.size(); ++i)
plugin->connect_port (handle, outputs.getUnchecked(i),
i < buffer.getNumChannels() ? buffer.getSampleData (i) : nullptr);
i < buffer.getNumChannels() ? buffer.getWritePointer (i) : nullptr);
plugin->run (handle, numSamples);
return;
@@ -312,7 +312,7 @@ public:
tempBuffer.clear();
for (int i = 0; i < outputs.size(); ++i)
plugin->connect_port (handle, outputs.getUnchecked(i), tempBuffer.getSampleData (i));
plugin->connect_port (handle, outputs.getUnchecked(i), tempBuffer.getWritePointer (i));
plugin->run_adding (handle, numSamples);


+ 2
- 2
source/modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -339,7 +339,7 @@ namespace VST3BufferExchange
*/
void associateBufferTo (Steinberg::Vst::AudioBusBuffers& vstBuffers,
Bus& bus,
const AudioSampleBuffer& buffer,
AudioSampleBuffer& buffer,
int numChannels, int channelStartOffset,
int sampleOffset = 0) noexcept
{
@@ -349,7 +349,7 @@ namespace VST3BufferExchange
bus.clearQuick();
for (int i = channelStartOffset; i < channelEnd; ++i)
bus.add (buffer.getSampleData (i, sampleOffset));
bus.add (buffer.getWritePointer (i, sampleOffset));
vstBuffers.channelBuffers32 = bus.getRawDataPointer();
vstBuffers.numChannels = numChannels;


+ 10
- 4
source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -175,9 +175,9 @@ static void setStateForAllBussesOfType (Vst::IComponent* component,
//==============================================================================
/** Assigns a complete AudioSampleBuffer's channels to an AudioBusBuffers' */
static void associateWholeBufferTo (Vst::AudioBusBuffers& vstBuffers, const AudioSampleBuffer& buffer) noexcept
static void associateWholeBufferTo (Vst::AudioBusBuffers& vstBuffers, AudioSampleBuffer& buffer) noexcept
{
vstBuffers.channelBuffers32 = buffer.getArrayOfChannels();
vstBuffers.channelBuffers32 = buffer.getArrayOfWritePointers();
vstBuffers.numChannels = buffer.getNumChannels();
vstBuffers.silenceFlags = 0;
}
@@ -224,6 +224,8 @@ static void toProcessContext (Vst::ProcessContext& context, AudioPlayHead* playH
}
break;
case AudioPlayHead::fpsUnknown: break;
default: jassertfalse; break; // New frame rate?
}
@@ -1634,7 +1636,11 @@ public:
bool hasEditor() const override
{
ComSmartPtr<IPlugView> view (tryCreatingView()); //N.B.: Must use a ComSmartPtr to not delete the view from the plugin permanently!
// (if possible, avoid creating a second instance of the editor, because that crashes some plugins)
if (getActiveEditor() != nullptr)
return true;
ComSmartPtr<IPlugView> view (tryCreatingView());
return view != nullptr;
}
@@ -1752,7 +1758,7 @@ private:
//==============================================================================
VST3ModuleHandle::Ptr module;
friend class VST3HostContext;
friend VST3HostContext;
ComSmartPtr<VST3HostContext> host;
// Information objects:


+ 3
- 3
source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -1062,17 +1062,17 @@ public:
if ((effect->flags & effFlagsCanReplacing) != 0)
{
effect->processReplacing (effect, buffer.getArrayOfChannels(), buffer.getArrayOfChannels(), numSamples);
effect->processReplacing (effect, buffer.getArrayOfWritePointers(), buffer.getArrayOfWritePointers(), numSamples);
}
else
{
tempBuffer.setSize (effect->numOutputs, numSamples);
tempBuffer.clear();
effect->process (effect, buffer.getArrayOfChannels(), tempBuffer.getArrayOfChannels(), numSamples);
effect->process (effect, buffer.getArrayOfWritePointers(), tempBuffer.getArrayOfWritePointers(), numSamples);
for (int i = effect->numOutputs; --i >= 0;)
buffer.copyFrom (i, 0, tempBuffer.getSampleData (i), numSamples);
buffer.copyFrom (i, 0, tempBuffer.getReadPointer (i), numSamples);
}
}
else


+ 4
- 4
source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp View File

@@ -175,7 +175,7 @@ public:
void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>&, const int numSamples)
{
float* data = sharedBufferChans.getSampleData (channel, 0);
float* data = sharedBufferChans.getWritePointer (channel, 0);
for (int i = numSamples; --i >= 0;)
{
@@ -219,7 +219,7 @@ public:
void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray <MidiBuffer>& sharedMidiBuffers, const int numSamples)
{
for (int i = totalChans; --i >= 0;)
channels[i] = sharedBufferChans.getSampleData (audioChannelsToUse.getUnchecked (i), 0);
channels[i] = sharedBufferChans.getWritePointer (audioChannelsToUse.getUnchecked (i), 0);
AudioSampleBuffer buffer (channels, totalChans, numSamples);
@@ -230,8 +230,8 @@ public:
AudioProcessor* const processor;
private:
Array <int> audioChannelsToUse;
HeapBlock <float*> channels;
Array<int> audioChannelsToUse;
HeapBlock<float*> channels;
int totalChans;
int midiBufferToUse;


+ 1
- 1
source/modules/juce_core/files/juce_File.cpp View File

@@ -754,7 +754,7 @@ String File::createLegalPathName (const String& original)
String s (original);
String start;
if (s[1] == ':')
if (s.isNotEmpty() && s[1] == ':')
{
start = s.substring (0, 2);
s = s.substring (2);


+ 34
- 1
source/modules/juce_core/maths/juce_Range.h View File

@@ -34,6 +34,9 @@
/** A general-purpose range object, that simply represents any linear range with
a start and end point.
Note that when checking whether values fall within the range, the start value is
considered to be inclusive, and the end of the range exclusive.
The templated parameter is expected to be a primitive integer or floating point
type, though class types could also be used if they behave in a number-like way.
*/
@@ -210,7 +213,10 @@ public:
return jlimit (start, end, value);
}
/** Returns true if the given range lies entirely inside this range. */
/** Returns true if the given range lies entirely inside this range.
When making this comparison, the start value is considered to be inclusive,
and the end of the range exclusive.
*/
bool contains (Range other) const noexcept
{
return start <= other.start && end >= other.end;
@@ -237,6 +243,13 @@ public:
jmax (end, other.end));
}
/** Returns the smallest range that contains both this one and the given value. */
Range getUnionWith (const ValueType valueToInclude) const noexcept
{
return Range (jmin (valueToInclude, start),
jmax (valueToInclude, end));
}
/** Returns a given range, after moving it forwards or backwards to fit it
within this range.
@@ -255,6 +268,26 @@ public:
: rangeToConstrain.movedToStartAt (jlimit (start, end - otherLen, rangeToConstrain.getStart()));
}
/** Scans an array of values for its min and max, and returns these as a Range. */
static Range findMinAndMax (const ValueType* values, int numValues) noexcept
{
if (numValues <= 0)
return Range();
const ValueType first (*values++);
Range r (first, first);
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
{
const ValueType v (*values++);
if (r.end < v) r.end = v;
if (v < r.start) r.start = v;
}
return r;
}
private:
//==============================================================================
ValueType start, end;


+ 7
- 2
source/modules/juce_core/memory/juce_MemoryBlock.cpp View File

@@ -127,8 +127,7 @@ void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
{
if (newSize <= 0)
{
data.free();
size = 0;
reset();
}
else
{
@@ -149,6 +148,12 @@ void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
}
}
void MemoryBlock::reset()
{
data.free();
size = 0;
}
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
{
if (size < minimumSize)


+ 6
- 3
source/modules/juce_core/memory/juce_MemoryBlock.h View File

@@ -108,9 +108,9 @@ public:
/** Resizes the memory block.
This will try to keep as much of the block's current content as it can,
and can optionally be made to clear any new space that gets allocated at
the end of the block.
Any data that is present in both the old and new sizes will be retained.
When enlarging the block, the new space that is allocated at the end can either be
cleared, or left uninitialised.
@param newSize the new desired size for the block
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
@@ -133,6 +133,9 @@ public:
void ensureSize (const size_t minimumSize,
bool initialiseNewSpaceToZero = false);
/** Frees all the blocks data, setting its size to 0. */
void reset();
//==============================================================================
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.


+ 1
- 6
source/modules/juce_core/network/juce_MACAddress.h View File

@@ -32,12 +32,7 @@
//==============================================================================
/**
A wrapper for a streaming (TCP) socket.
This allows low-level use of sockets; for an easier-to-use messaging layer on top of
sockets, you could also try the InterprocessConnection class.
@see DatagramSocket, InterprocessConnection, InterprocessConnectionServer
Represents a MAC network card adapter address ID.
*/
class JUCE_API MACAddress
{


+ 85
- 75
source/modules/juce_core/network/juce_URL.cpp View File

@@ -75,8 +75,7 @@ URL::URL (const URL& other)
postData (other.postData),
parameterNames (other.parameterNames),
parameterValues (other.parameterValues),
filesToUpload (other.filesToUpload),
mimeTypes (other.mimeTypes)
filesToUpload (other.filesToUpload)
{
}
@@ -87,7 +86,6 @@ URL& URL::operator= (const URL& other)
parameterNames = other.parameterNames;
parameterValues = other.parameterValues;
filesToUpload = other.filesToUpload;
mimeTypes = other.mimeTypes;
return *this;
}
@@ -98,8 +96,7 @@ bool URL::operator== (const URL& other) const
&& postData == other.postData
&& parameterNames == other.parameterNames
&& parameterValues == other.parameterValues
&& filesToUpload == other.filesToUpload
&& mimeTypes == other.mimeTypes;
&& filesToUpload == other.filesToUpload;
}
bool URL::operator!= (const URL& other) const
@@ -156,62 +153,6 @@ namespace URLHelpers
return url.indexOfChar (findStartOfNetLocation (url), '/') + 1;
}
static void createHeadersAndPostData (const URL& url, String& headers, MemoryBlock& postData)
{
MemoryOutputStream data (postData, false);
if (url.getFilesToUpload().size() > 0)
{
// need to upload some files, so do it as multi-part...
const String boundary (String::toHexString (Random::getSystemRandom().nextInt64()));
headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
data << "--" << boundary;
for (int i = 0; i < url.getParameterNames().size(); ++i)
{
data << "\r\nContent-Disposition: form-data; name=\""
<< url.getParameterNames() [i]
<< "\"\r\n\r\n"
<< url.getParameterValues() [i]
<< "\r\n--"
<< boundary;
}
for (int i = 0; i < url.getFilesToUpload().size(); ++i)
{
const File file (url.getFilesToUpload().getAllValues() [i]);
const String paramName (url.getFilesToUpload().getAllKeys() [i]);
data << "\r\nContent-Disposition: form-data; name=\"" << paramName
<< "\"; filename=\"" << file.getFileName() << "\"\r\n";
const String mimeType (url.getMimeTypesOfUploadFiles()
.getValue (paramName, String()));
if (mimeType.isNotEmpty())
data << "Content-Type: " << mimeType << "\r\n";
data << "Content-Transfer-Encoding: binary\r\n\r\n"
<< file << "\r\n--" << boundary;
}
data << "--\r\n";
}
else
{
data << getMangledParameters (url)
<< url.getPostData();
// if the user-supplied headers didn't contain a content-type, add one now..
if (! headers.containsIgnoreCase ("Content-Type"))
headers << "Content-Type: application/x-www-form-urlencoded\r\n";
headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
}
}
static void concatenatePaths (String& path, const String& suffix)
{
if (! path.endsWithChar ('/'))
@@ -296,6 +237,64 @@ URL URL::getChildURL (const String& subPath) const
return u;
}
void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPostData) const
{
MemoryOutputStream data (headersAndPostData, false);
data << URLHelpers::getMangledParameters (*this);
if (filesToUpload.size() > 0)
{
// (this doesn't currently support mixing custom post-data with uploads..)
jassert (postData.isEmpty());
const String boundary (String::toHexString (Random::getSystemRandom().nextInt64()));
headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
data << "--" << boundary;
for (int i = 0; i < parameterNames.size(); ++i)
{
data << "\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
<< "\"\r\n\r\n" << parameterValues[i]
<< "\r\n--" << boundary;
}
for (int i = 0; i < filesToUpload.size(); ++i)
{
const Upload& f = *filesToUpload.getObjectPointerUnchecked(i);
data << "\r\nContent-Disposition: form-data; name=\"" << f.parameterName
<< "\"; filename=\"" << f.filename << "\"\r\n";
if (f.mimeType.isNotEmpty())
data << "Content-Type: " << f.mimeType << "\r\n";
data << "Content-Transfer-Encoding: binary\r\n\r\n";
if (f.data != nullptr)
data << *f.data;
else
data << f.file;
data << "\r\n--" << boundary;
}
data << "--\r\n";
}
else
{
data << postData;
// if the user-supplied headers didn't contain a content-type, add one now..
if (! headers.containsIgnoreCase ("Content-Type"))
headers << "Content-Type: application/x-www-form-urlencoded\r\n";
headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
}
}
//==============================================================================
bool URL::isProbablyAWebsiteURL (const String& possibleURL)
{
@@ -339,7 +338,7 @@ InputStream* URL::createInputStream (const bool usePostCommand,
headers << "\r\n";
if (usePostCommand)
URLHelpers::createHeadersAndPostData (*this, headers, headersAndPostData);
createHeadersAndPostData (headers, headersAndPostData);
if (! headers.endsWithChar ('\n'))
headers << "\r\n";
@@ -394,33 +393,44 @@ URL URL::withParameter (const String& parameterName,
return u;
}
URL URL::withFileToUpload (const String& parameterName,
const File& fileToUpload,
const String& mimeType) const
URL URL::withPOSTData (const String& newPostData) const
{
jassert (mimeType.isNotEmpty()); // You need to supply a mime type!
URL u (*this);
u.filesToUpload.set (parameterName, fileToUpload.getFullPathName());
u.mimeTypes.set (parameterName, mimeType);
u.postData = newPostData;
return u;
}
URL URL::withPOSTData (const String& newPostData) const
URL::Upload::Upload (const String& param, const String& name,
const String& mime, const File& f, MemoryBlock* mb)
: parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
{
jassert (mimeType.isNotEmpty()); // You need to supply a mime type!
}
URL URL::withUpload (Upload* const f) const
{
URL u (*this);
u.postData = newPostData;
for (int i = u.filesToUpload.size(); --i >= 0;)
if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName)
u.filesToUpload.remove (i);
u.filesToUpload.add (f);
return u;
}
const StringPairArray& URL::getFilesToUpload() const
URL URL::withFileToUpload (const String& parameterName, const File& fileToUpload,
const String& mimeType) const
{
return filesToUpload;
return withUpload (new Upload (parameterName, fileToUpload.getFileName(),
mimeType, fileToUpload, nullptr));
}
const StringPairArray& URL::getMimeTypesOfUploadFiles() const
URL URL::withDataToUpload (const String& parameterName, const String& filename,
const MemoryBlock& fileContentToUpload, const String& mimeType) const
{
return mimeTypes;
return withUpload (new Upload (parameterName, filename, mimeType, File(),
new MemoryBlock (fileContentToUpload)));
}
//==============================================================================


+ 33
- 14
source/modules/juce_core/network/juce_URL.h View File

@@ -137,18 +137,35 @@ public:
URL withParameter (const String& parameterName,
const String& parameterValue) const;
/** Returns a copy of this URl, with a file-upload type parameter added to it.
/** Returns a copy of this URL, with a file-upload type parameter added to it.
When performing a POST where one of your parameters is a binary file, this
lets you specify the file.
Note that the filename is stored, but the file itself won't actually be read
until this URL is later used to create a network input stream.
until this URL is later used to create a network input stream. If you want to
upload data from memory, use withDataToUpload().
@see withDataToUpload
*/
URL withFileToUpload (const String& parameterName,
const File& fileToUpload,
const String& mimeType) const;
/** Returns a copy of this URL, with a file-upload type parameter added to it.
When performing a POST where one of your parameters is a binary file, this
lets you specify the file content.
Note that the filename parameter should not be a full path, it's just the
last part of the filename.
@see withFileToUpload
*/
URL withDataToUpload (const String& parameterName,
const String& filename,
const MemoryBlock& fileContentToUpload,
const String& mimeType) const;
/** Returns an array of the names of all the URL's parameters.
E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would
@@ -175,17 +192,6 @@ public:
*/
const StringArray& getParameterValues() const noexcept { return parameterValues; }
/** Returns the set of files that should be uploaded as part of a POST operation.
This is the set of files that were added to the URL with the withFileToUpload()
method.
*/
const StringPairArray& getFilesToUpload() const;
/** Returns the set of mime types associated with each of the upload files.
*/
const StringPairArray& getMimeTypesOfUploadFiles() const;
/** Returns a copy of this URL, with a block of data to send as the POST data.
If you're setting the POST data, be careful not to have any parameters set
@@ -343,10 +349,23 @@ private:
//==============================================================================
String url, postData;
StringArray parameterNames, parameterValues;
StringPairArray filesToUpload, mimeTypes;
struct Upload : public ReferenceCountedObject
{
Upload (const String&, const String&, const String&, const File&, MemoryBlock*);
String parameterName, filename, mimeType;
File file;
ScopedPointer<MemoryBlock> data;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Upload)
};
ReferenceCountedArray<Upload> filesToUpload;
URL (const String&, int);
void addParameter (const String&, const String&);
void createHeadersAndPostData (String&, MemoryBlock&) const;
URL withUpload (Upload*) const;
JUCE_LEAK_DETECTOR (URL)
};


+ 1
- 0
source/modules/juce_core/system/juce_SystemStats.h View File

@@ -58,6 +58,7 @@ public:
MacOSX_10_6 = 0x1006,
MacOSX_10_7 = 0x1007,
MacOSX_10_8 = 0x1008,
MacOSX_10_9 = 0x1009,
Win2000 = 0x4105,
WinXP = 0x4106,


+ 6
- 14
source/modules/juce_core/threads/juce_ReadWriteLock.cpp View File

@@ -105,18 +105,8 @@ void ReadWriteLock::enterWrite() const noexcept
const Thread::ThreadID threadId = Thread::getCurrentThreadId();
const SpinLock::ScopedLockType sl (accessLock);
for (;;)
while (! tryEnterWriteInternal (threadId))
{
if (readerThreads.size() + numWriters == 0
|| threadId == writerThreadId
|| (readerThreads.size() == 1
&& readerThreads.getReference(0).threadID == threadId))
{
writerThreadId = threadId;
++numWriters;
break;
}
++numWaitingWriters;
accessLock.exit();
waitEvent.wait (100);
@@ -127,13 +117,15 @@ void ReadWriteLock::enterWrite() const noexcept
bool ReadWriteLock::tryEnterWrite() const noexcept
{
const Thread::ThreadID threadId = Thread::getCurrentThreadId();
const SpinLock::ScopedLockType sl (accessLock);
return tryEnterWriteInternal (Thread::getCurrentThreadId());
}
bool ReadWriteLock::tryEnterWriteInternal (Thread::ThreadID threadId) const noexcept
{
if (readerThreads.size() + numWriters == 0
|| threadId == writerThreadId
|| (readerThreads.size() == 1
&& readerThreads.getReference(0).threadID == threadId))
|| (readerThreads.size() == 1 && readerThreads.getReference(0).threadID == threadId))
{
writerThreadId = threadId;
++numWriters;


+ 2
- 0
source/modules/juce_core/threads/juce_ReadWriteLock.h View File

@@ -143,6 +143,8 @@ private:
mutable Array <ThreadRecursionCount> readerThreads;
bool tryEnterWriteInternal (Thread::ThreadID) const noexcept;
JUCE_DECLARE_NON_COPYABLE (ReadWriteLock)
};


+ 1
- 2
source/modules/juce_data_structures/values/juce_Value.h View File

@@ -75,8 +75,7 @@ public:
operator var() const;
/** Returns the value as a string.
This is alternative to writing things like "myValue.getValue().toString()".
This is a shortcut for "myValue.getValue().toString()".
*/
String toString() const;


+ 1
- 1
source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp View File

@@ -77,7 +77,7 @@ private:
}
}
JUCE_DECLARE_NON_COPYABLE (ChildProcessPingThread)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessPingThread)
};
//==============================================================================


+ 1
- 1
source/modules/juce_events/messages/juce_MessageManager.h View File

@@ -128,7 +128,7 @@ public:
*/
Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; }
/** Returns true if the caller thread has currenltly got the message manager locked.
/** Returns true if the caller thread has currently got the message manager locked.
see the MessageManagerLock class for more info about this.


+ 0
- 26
source/modules/juce_events/timers/juce_Timer.cpp View File

@@ -295,20 +295,12 @@ Timer::TimerThread* Timer::TimerThread::instance = nullptr;
Timer::TimerThread::LockType Timer::TimerThread::lock;
//==============================================================================
#if JUCE_DEBUG
static SortedSet <Timer*> activeTimers;
#endif
Timer::Timer() noexcept
: countdownMs (0),
periodMs (0),
previous (nullptr),
next (nullptr)
{
#if JUCE_DEBUG
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
activeTimers.add (this);
#endif
}
Timer::Timer (const Timer&) noexcept
@@ -317,30 +309,17 @@ Timer::Timer (const Timer&) noexcept
previous (nullptr),
next (nullptr)
{
#if JUCE_DEBUG
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
activeTimers.add (this);
#endif
}
Timer::~Timer()
{
stopTimer();
#if JUCE_DEBUG
activeTimers.removeValue (this);
#endif
}
void Timer::startTimer (const int interval) noexcept
{
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
#if JUCE_DEBUG
// this isn't a valid object! Your timer might be a dangling pointer or something..
jassert (activeTimers.contains (this));
#endif
if (periodMs == 0)
{
countdownMs = interval;
@@ -357,11 +336,6 @@ void Timer::stopTimer() noexcept
{
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
#if JUCE_DEBUG
// this isn't a valid object! Your timer might be a dangling pointer or something..
jassert (activeTimers.contains (this));
#endif
if (periodMs > 0)
{
TimerThread::remove (this);


+ 9
- 0
source/modules/juce_graphics/fonts/juce_CustomTypeface.h View File

@@ -36,6 +36,11 @@
If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface()
to copy glyphs into this face.
NOTE! For most people this class is almost certainly NOT the right tool to use!
If what you want to do is to embed a font into your exe, then your best plan is
probably to embed your TTF/OTF font file into your binary using the Introjucer,
and then call Typeface::createSystemTypefaceFor() to load it from memory.
@see Typeface, Font
*/
class JUCE_API CustomTypeface : public Typeface
@@ -108,6 +113,10 @@ public:
/** Saves this typeface as a Juce-formatted font file.
A CustomTypeface can be created to reload the data that is written - see the CustomTypeface
constructor.
NOTE! Since this class was written, support was added for loading real font files from
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
is more appropriate than using this class to store it in a proprietory format.
*/
bool writeToStream (OutputStream& outputStream);


+ 11
- 6
source/modules/juce_graphics/geometry/juce_Path.cpp View File

@@ -254,6 +254,11 @@ Rectangle<float> Path::getBoundsTransformed (const AffineTransform& transform) c
}
//==============================================================================
void Path::preallocateSpace (int numExtraCoordsToMakeSpaceFor)
{
data.ensureAllocatedSize ((int) numElements + numExtraCoordsToMakeSpaceFor);
}
void Path::startNewSubPath (const float x, const float y)
{
JUCE_CHECK_COORDS_ARE_VALID (x, y);
@@ -263,7 +268,7 @@ void Path::startNewSubPath (const float x, const float y)
else
bounds.extend (x, y);
data.ensureAllocatedSize ((int) numElements + 3);
preallocateSpace (3);
data.elements [numElements++] = moveMarker;
data.elements [numElements++] = x;
@@ -282,7 +287,7 @@ void Path::lineTo (const float x, const float y)
if (numElements == 0)
startNewSubPath (0, 0);
data.ensureAllocatedSize ((int) numElements + 3);
preallocateSpace (3);
data.elements [numElements++] = lineMarker;
data.elements [numElements++] = x;
@@ -305,7 +310,7 @@ void Path::quadraticTo (const float x1, const float y1,
if (numElements == 0)
startNewSubPath (0, 0);
data.ensureAllocatedSize ((int) numElements + 5);
preallocateSpace (5);
data.elements [numElements++] = quadMarker;
data.elements [numElements++] = x1;
@@ -334,7 +339,7 @@ void Path::cubicTo (const float x1, const float y1,
if (numElements == 0)
startNewSubPath (0, 0);
data.ensureAllocatedSize ((int) numElements + 7);
preallocateSpace (7);
data.elements [numElements++] = cubicMarker;
data.elements [numElements++] = x1;
@@ -362,7 +367,7 @@ void Path::closeSubPath()
if (numElements > 0
&& data.elements [numElements - 1] != closeSubPathMarker)
{
data.ensureAllocatedSize ((int) numElements + 1);
preallocateSpace (1);
data.elements [numElements++] = closeSubPathMarker;
}
}
@@ -399,7 +404,7 @@ void Path::addRectangle (const float x, const float y,
if (w < 0) std::swap (x1, x2);
if (h < 0) std::swap (y1, y2);
data.ensureAllocatedSize ((int) numElements + 13);
preallocateSpace (13);
if (numElements == 0)
{


+ 13
- 2
source/modules/juce_graphics/geometry/juce_Path.h View File

@@ -560,6 +560,18 @@ public:
*/
void swapWithPath (Path&) noexcept;
//==============================================================================
/** Preallocates enough space for adding the given number of coordinates to the path.
If you're about to add a large number of lines or curves to the path, it can make
the task much more efficient to call this first and avoid costly reallocations
as the structure grows.
The actual value to pass is a bit tricky to calculate because the space required
depends on what you're adding - e.g. each lineTo() or startNewSubPath() will
require 3 coords (x, y and a type marker). Each quadraticTo() will need 5, and
a cubicTo() will require 7. Closing a sub-path will require 1.
*/
void preallocateSpace (int numExtraCoordsToMakeSpaceFor);
//==============================================================================
/** Applies a 2D transform to all the vertices in the path.
@@ -742,12 +754,11 @@ public:
*/
void restoreFromString (StringRef stringVersion);
private:
//==============================================================================
friend class PathFlatteningIterator;
friend class Path::Iterator;
ArrayAllocationBase <float, DummyCriticalSection> data;
ArrayAllocationBase<float, DummyCriticalSection> data;
size_t numElements;
struct PathBounds


+ 54
- 45
source/modules/juce_graphics/native/juce_RenderingHelpers.h View File

@@ -164,53 +164,16 @@ public:
//==============================================================================
void drawGlyph (RenderTargetType& target, const Font& font, const int glyphNumber, Point<float> pos)
{
++accessCounter;
CachedGlyphType* glyph = nullptr;
const ScopedReadLock srl (lock);
for (int i = glyphs.size(); --i >= 0;)
{
CachedGlyphType* const g = glyphs.getUnchecked (i);
if (g->glyph == glyphNumber && g->font == font)
{
glyph = g;
++hits;
break;
}
}
if (glyph == nullptr)
if (ReferenceCountedObjectPtr<CachedGlyphType> glyph = findOrCreateGlyph (font, glyphNumber))
{
++misses;
const ScopedWriteLock swl (lock);
if (hits.value + misses.value > glyphs.size() * 16)
{
if (misses.value * 2 > hits.value)
addNewGlyphSlots (32);
hits.set (0);
misses.set (0);
glyph = glyphs.getLast();
}
else
{
glyph = findLeastRecentlyUsedGlyph();
}
jassert (glyph != nullptr);
glyph->generate (font, glyphNumber);
glyph->lastAccessCount = ++accessCounter;
glyph->draw (target, pos);
}
glyph->lastAccessCount = accessCounter.value;
glyph->draw (target, pos);
}
void reset()
{
const ScopedWriteLock swl (lock);
const ScopedLock sl (lock);
glyphs.clear();
addNewGlyphSlots (120);
hits.set (0);
@@ -219,9 +182,54 @@ public:
private:
friend struct ContainerDeletePolicy<CachedGlyphType>;
OwnedArray<CachedGlyphType> glyphs;
ReferenceCountedArray<CachedGlyphType> glyphs;
Atomic<int> accessCounter, hits, misses;
ReadWriteLock lock;
CriticalSection lock;
ReferenceCountedObjectPtr<CachedGlyphType> findOrCreateGlyph (const Font& font, int glyphNumber)
{
const ScopedLock sl (lock);
if (CachedGlyphType* g = findExistingGlyph (font, glyphNumber))
{
++hits;
return g;
}
++misses;
CachedGlyphType* g = getGlyphForReuse();
jassert (g != nullptr);
g->generate (font, glyphNumber);
return g;
}
CachedGlyphType* findExistingGlyph (const Font& font, int glyphNumber) const
{
for (int i = 0; i < glyphs.size(); ++i)
{
CachedGlyphType* const g = glyphs.getUnchecked (i);
if (g->glyph == glyphNumber && g->font == font)
return g;
}
return nullptr;
}
CachedGlyphType* getGlyphForReuse()
{
if (hits.value + misses.value > glyphs.size() * 16)
{
if (misses.value * 2 > hits.value)
addNewGlyphSlots (32);
hits.set (0);
misses.set (0);
return glyphs.getLast();
}
return findLeastRecentlyUsedGlyph();
}
void addNewGlyphSlots (int num)
{
@@ -240,7 +248,8 @@ private:
{
CachedGlyphType* const glyph = glyphs.getUnchecked(i);
if (glyph->lastAccessCount <= oldestCounter)
if (glyph->lastAccessCount <= oldestCounter
&& glyph->getReferenceCount() == 1)
{
oldestCounter = glyph->lastAccessCount;
oldest = glyph;
@@ -262,7 +271,7 @@ private:
//==============================================================================
/** Caches a glyph as an edge-table. */
template <class RendererType>
class CachedGlyphEdgeTable
class CachedGlyphEdgeTable : public ReferenceCountedObject
{
public:
CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}


+ 2
- 1
source/modules/juce_graphics/native/juce_win32_Fonts.cpp View File

@@ -120,7 +120,8 @@ namespace TTFNameExtractor
for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (offsetTable.numTables); ++i)
{
TableDirectory tableDirectory = { 0 };
TableDirectory tableDirectory;
zerostruct (tableDirectory);
input.read (&tableDirectory, sizeof (tableDirectory));
if (String (tableDirectory.tag, sizeof (tableDirectory.tag)).equalsIgnoreCase ("name"))


+ 4
- 2
source/modules/juce_gui_basics/buttons/juce_Button.h View File

@@ -360,10 +360,12 @@ public:
{
virtual ~LookAndFeelMethods() {}
virtual void drawButtonBackground (Graphics&, Button& button, const Colour& backgroundColour,
virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool isMouseOverButton, bool isButtonDown) = 0;
virtual Font getTextButtonFont (TextButton& button) = 0;
virtual Font getTextButtonFont (TextButton&) = 0;
virtual void changeTextButtonWidthToFitText (TextButton&, int newHeight) = 0;
/** Draws the text for a TextButton. */
virtual void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) = 0;


+ 1
- 1
source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp View File

@@ -74,7 +74,7 @@ Font HyperlinkButton::getFontToUse() const
void HyperlinkButton::changeWidthToFitText()
{
setSize (getFontToUse().getStringWidth (getName()) + 6, getHeight());
setSize (getFontToUse().getStringWidth (getButtonText()) + 6, getHeight());
}
void HyperlinkButton::colourChanged()


+ 10
- 16
source/modules/juce_gui_basics/buttons/juce_TextButton.cpp View File

@@ -22,6 +22,10 @@
==============================================================================
*/
TextButton::TextButton() : Button (String())
{
}
TextButton::TextButton (const String& name, const String& toolTip)
: Button (name)
{
@@ -32,21 +36,15 @@ TextButton::~TextButton()
{
}
void TextButton::paintButton (Graphics& g,
bool isMouseOverButton,
bool isButtonDown)
void TextButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown)
{
LookAndFeel& lf = getLookAndFeel();
lf.drawButtonBackground (g, *this,
findColour (getToggleState() ? buttonOnColourId
: buttonColourId),
isMouseOverButton,
isButtonDown);
lf.drawButtonText (g, *this,
isMouseOverButton,
isButtonDown);
findColour (getToggleState() ? buttonOnColourId : buttonColourId),
isMouseOverButton, isButtonDown);
lf.drawButtonText (g, *this, isMouseOverButton, isButtonDown);
}
void TextButton::colourChanged()
@@ -61,9 +59,5 @@ Font TextButton::getFont()
void TextButton::changeWidthToFitText (const int newHeight)
{
if (newHeight >= 0)
setSize (jmax (1, getWidth()), newHeight);
setSize (getFont().getStringWidth (getButtonText()) + getHeight(),
getHeight());
getLookAndFeel().changeTextButtonWidthToFitText (*this, newHeight);
}

+ 7
- 7
source/modules/juce_gui_basics/buttons/juce_TextButton.h View File

@@ -37,17 +37,18 @@ class JUCE_API TextButton : public Button
{
public:
//==============================================================================
/** Creates a TextButton.
/** Creates a TextButton. */
TextButton();
/** Creates a TextButton.
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
@param toolTip an optional string to use as a toolip
@see Button
*/
TextButton (const String& buttonName = String::empty,
const String& toolTip = String::empty);
explicit TextButton (const String& buttonName,
const String& toolTip = String::empty);
/** Destructor. */
~TextButton();
@@ -74,19 +75,18 @@ public:
//==============================================================================
/** Resizes the button to fit neatly around its current text.
If newHeight is >= 0, the button's height will be changed to this
value. If it's less than zero, its height will be unaffected.
*/
void changeWidthToFitText (int newHeight = -1);
/** This can be overridden to use different fonts than the default one.
Note that you'll need to set the font's size appropriately, too.
*/
virtual Font getFont();
protected:
//==============================================================================
/** @internal */
void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override;
/** @internal */


+ 9
- 4
source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -69,13 +69,15 @@ public:
if (newState.width <= 0) newState.width = 100;
if (newState.height <= 0) newState.height = 100;
Point<float> viewboxXY;
if (xml->hasAttribute ("viewBox"))
{
const String viewBoxAtt (xml->getStringAttribute ("viewBox"));
String::CharPointerType viewParams (viewBoxAtt.getCharPointer());
Point<float> vxy, vwh;
Point<float> vwh;
if (parseCoords (viewParams, vxy, true)
if (parseCoords (viewParams, viewboxXY, true)
&& parseCoords (viewParams, vwh, true)
&& vwh.x > 0
&& vwh.y > 0)
@@ -105,7 +107,7 @@ public:
}
newState.transform = RectanglePlacement (placementFlags)
.getTransformToFit (Rectangle<float> (vxy.x, vxy.y, vwh.x, vwh.y),
.getTransformToFit (Rectangle<float> (viewboxXY.x, viewboxXY.y, vwh.x, vwh.y),
Rectangle<float> (newState.width, newState.height))
.followedBy (newState.transform);
}
@@ -118,7 +120,10 @@ public:
newState.parseSubElements (xml, *drawable);
drawable->setContentArea (RelativeRectangle (Rectangle<float> (newState.viewBoxW, newState.viewBoxH)));
drawable->setContentArea (RelativeRectangle (RelativeCoordinate (viewboxXY.x),
RelativeCoordinate (viewboxXY.x + newState.viewBoxW),
RelativeCoordinate (viewboxXY.y),
RelativeCoordinate (viewboxXY.y + newState.viewBoxH)));
drawable->resetBoundingBoxToContentArea();
return drawable;


+ 10
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -243,6 +243,16 @@ Font LookAndFeel_V2::getTextButtonFont (TextButton& button)
return button.getFont();
}
void LookAndFeel_V2::changeTextButtonWidthToFitText (TextButton& b, int newHeight)
{
if (newHeight >= 0)
b.setSize (jmax (1, b.getWidth()), newHeight);
else
newHeight = b.getHeight();
b.setSize (getTextButtonFont (b).getStringWidth (b.getButtonText()) + newHeight, newHeight);
}
void LookAndFeel_V2::drawButtonText (Graphics& g, TextButton& button, bool /*isMouseOverButton*/, bool /*isButtonDown*/)
{
Font font (getTextButtonFont (button));


+ 1
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h View File

@@ -46,6 +46,7 @@ public:
void drawButtonText (Graphics&, TextButton& button,
bool isMouseOverButton, bool isButtonDown) override;
void changeTextButtonWidthToFitText (TextButton&, int newHeight) override;
void drawToggleButton (Graphics&, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) override;


+ 2
- 1
source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp View File

@@ -98,7 +98,6 @@ void FileChooser::showPlatformDialog (Array<File>& results,
args.add (startPath);
args.add (filters.replaceCharacter (';', ' '));
args.add ("2>/dev/null");
}
else
{
@@ -132,6 +131,8 @@ void FileChooser::showPlatformDialog (Array<File>& results,
args.add ("--filename=" + file.getFileName());
}
args.add ("2>/dev/null");
ChildProcess child;
if (child.start (args, ChildProcess::wantStdOut))


+ 6
- 2
source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -141,7 +141,7 @@ public:
[window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)];
if (component.isAlwaysOnTop())
[window setLevel: NSFloatingWindowLevel];
setAlwaysOnTop (true);
[window setContentView: view];
[window setAutodisplay: YES];
@@ -202,7 +202,9 @@ public:
{
if (shouldBeVisible)
{
++insideToFrontCall;
[window orderFront: nil];
--insideToFrontCall;
handleBroughtToFront();
}
else
@@ -439,8 +441,10 @@ public:
bool setAlwaysOnTop (bool alwaysOnTop) override
{
if (! isSharedWindow)
[window setLevel: alwaysOnTop ? NSFloatingWindowLevel
[window setLevel: alwaysOnTop ? ((getStyleFlags() & windowIsTemporary) != 0 ? NSPopUpMenuWindowLevel
: NSFloatingWindowLevel)
: NSNormalWindowLevel];
return true;
}


+ 111
- 30
source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -102,17 +102,38 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
#endif
#ifndef MONITOR_DPI_TYPE
enum Monitor_DPI_Type
{
MDT_Effective_DPI = 0,
MDT_Angular_DPI = 1,
MDT_Raw_DPI = 2,
MDT_Default = MDT_Effective_DPI
};
enum Process_DPI_Awareness
{
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
};
#endif
typedef BOOL (WINAPI* RegisterTouchWindowFunc) (HWND, ULONG);
typedef BOOL (WINAPI* GetTouchInputInfoFunc) (HTOUCHINPUT, UINT, TOUCHINPUT*, int);
typedef BOOL (WINAPI* CloseTouchInputHandleFunc) (HTOUCHINPUT);
typedef BOOL (WINAPI* GetGestureInfoFunc) (HGESTUREINFO, GESTUREINFO*);
typedef BOOL (WINAPI* SetProcessDPIAwareFunc)();
typedef BOOL (WINAPI* SetProcessDPIAwarenessFunc) (Process_DPI_Awareness);
typedef HRESULT (WINAPI* GetDPIForMonitorFunc) (HMONITOR, Monitor_DPI_Type, UINT*, UINT*);
static RegisterTouchWindowFunc registerTouchWindow = nullptr;
static GetTouchInputInfoFunc getTouchInputInfo = nullptr;
static CloseTouchInputHandleFunc closeTouchInputHandle = nullptr;
static GetGestureInfoFunc getGestureInfo = nullptr;
static SetProcessDPIAwareFunc setProcessDPIAware = nullptr;
static RegisterTouchWindowFunc registerTouchWindow = nullptr;
static GetTouchInputInfoFunc getTouchInputInfo = nullptr;
static CloseTouchInputHandleFunc closeTouchInputHandle = nullptr;
static GetGestureInfoFunc getGestureInfo = nullptr;
static SetProcessDPIAwareFunc setProcessDPIAware = nullptr;
static SetProcessDPIAwarenessFunc setProcessDPIAwareness = nullptr;
static GetDPIForMonitorFunc getDPIForMonitor = nullptr;
static bool hasCheckedForMultiTouch = false;
@@ -158,17 +179,33 @@ static void setDPIAwareness()
{
if (JUCEApplicationBase::isStandaloneApp())
{
if (setProcessDPIAware == nullptr)
if (setProcessDPIAwareness == nullptr)
{
setProcessDPIAware = (SetProcessDPIAwareFunc) getUser32Function ("SetProcessDPIAware");
HMODULE shcoreModule = GetModuleHandleA ("SHCore.dll");
if (shcoreModule != 0)
{
setProcessDPIAwareness = (SetProcessDPIAwarenessFunc) GetProcAddress (shcoreModule, "SetProcessDpiAwareness");
getDPIForMonitor = (GetDPIForMonitorFunc) GetProcAddress (shcoreModule, "GetDpiForMonitor");
if (setProcessDPIAwareness != nullptr && getDPIForMonitor != nullptr
// && SUCCEEDED (setProcessDPIAwareness (Process_Per_Monitor_DPI_Aware)))
&& SUCCEEDED (setProcessDPIAwareness (Process_System_DPI_Aware))) // (keep using this mode temporarily..)
return;
}
if (setProcessDPIAware != nullptr)
setProcessDPIAware();
if (setProcessDPIAware == nullptr)
{
setProcessDPIAware = (SetProcessDPIAwareFunc) getUser32Function ("SetProcessDPIAware");
if (setProcessDPIAware != nullptr)
setProcessDPIAware();
}
}
}
}
static double getDPI()
static double getGlobalDPI()
{
setDPIAwareness();
@@ -181,7 +218,7 @@ static double getDPI()
double Desktop::getDefaultMasterScale()
{
return JUCEApplicationBase::isStandaloneApp() ? getDPI() / 96.0
return JUCEApplicationBase::isStandaloneApp() ? getGlobalDPI() / 96.0
: 1.0;
}
@@ -1076,6 +1113,20 @@ public:
JUCE_DECLARE_NON_COPYABLE (JuceDropTarget)
};
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
static bool offerKeyMessageToJUCEWindow (MSG& m)
{
if (m.message == WM_KEYDOWN || m.message == WM_KEYUP)
if (Component::getCurrentlyFocusedComponent() != nullptr)
if (HWNDComponentPeer* h = getOwnerOfWindow (m.hwnd))
if (m.message == WM_KEYDOWN ? h->doKeyDown (m.wParam)
: h->doKeyUp (m.wParam))
return true;
return false;
}
#endif
private:
HWND hwnd, parentToAddTo;
ScopedPointer<DropShadower> shadower;
@@ -1973,28 +2024,25 @@ private:
used = handleKeyPress (extendedKeyModifier | (int) key, 0) || used;
break;
case VK_ADD:
case VK_SUBTRACT:
case VK_MULTIPLY:
case VK_DIVIDE:
case VK_SEPARATOR:
case VK_DECIMAL:
used = handleKeyUpOrDown (true);
break;
default:
used = handleKeyUpOrDown (true);
{
MSG msg;
if (! PeekMessage (&msg, hwnd, WM_CHAR, WM_DEADCHAR, PM_NOREMOVE))
{
// if there isn't a WM_CHAR or WM_DEADCHAR message pending, we need to
// manually generate the key-press event that matches this key-down.
const UINT keyChar = MapVirtualKey ((UINT) key, 2);
const UINT scanCode = MapVirtualKey ((UINT) key, 0);
BYTE keyState[256];
GetKeyboardState (keyState);
WCHAR text[16] = { 0 };
if (ToUnicode ((UINT) key, scanCode, keyState, text, 8, 0) != 1)
text[0] = 0;
const UINT keyChar = MapVirtualKey ((UINT) key, 2);
used = handleKeyPress ((int) LOWORD (keyChar), 0) || used;
used = handleKeyPress ((int) LOWORD (keyChar), (juce_wchar) text[0]) || used;
}
}
@@ -2246,6 +2294,10 @@ private:
}
}
void handleDPIChange() // happens when a window moves to a screen with a different DPI.
{
}
//==============================================================================
public:
static LRESULT CALLBACK windowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
@@ -2488,6 +2540,10 @@ private:
doSettingChange();
break;
case 0x2e0: // WM_DPICHANGED
handleDPIChange();
break;
case WM_INITMENU:
initialiseSysMenu ((HMENU) wParam);
break;
@@ -2890,6 +2946,10 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode)
return HWNDComponentPeer::isKeyDown (k);
}
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
bool offerKeyMessageToJUCEWindow (MSG& m) { return HWNDComponentPeer::offerKeyMessageToJUCEWindow (m); }
#endif
//==============================================================================
bool JUCE_CALLTYPE Process::isForegroundProcess()
{
@@ -3183,9 +3243,11 @@ void Desktop::setKioskComponent (Component* kioskModeComponent, bool enableOrDis
//==============================================================================
struct MonitorInfo
{
MonitorInfo (Rectangle<int> rect, bool main) noexcept : isMain (main), bounds (rect) {}
MonitorInfo (Rectangle<int> rect, bool main, double d) noexcept
: bounds (rect), dpi (d), isMain (main) {}
Rectangle<int> bounds;
double dpi;
bool isMain;
};
@@ -3195,7 +3257,17 @@ static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT r, LPARAM userIn
info.cbSize = sizeof (info);
GetMonitorInfo (hm, &info);
const bool isMain = (info.dwFlags & 1 /* MONITORINFOF_PRIMARY */) != 0;
((Array<MonitorInfo>*) userInfo)->add (MonitorInfo (rectangleFromRECT (*r), isMain));
double dpi = 0;
if (getDPIForMonitor != nullptr)
{
UINT dpiX = 0, dpiY = 0;
if (SUCCEEDED (getDPIForMonitor (hm, MDT_Default, &dpiX, &dpiY)))
dpi = (dpiX + dpiY) / 2.0;
}
((Array<MonitorInfo>*) userInfo)->add (MonitorInfo (rectangleFromRECT (*r), isMain, dpi));
return TRUE;
}
@@ -3207,8 +3279,10 @@ void Desktop::Displays::findDisplays (float masterScale)
Array<MonitorInfo> monitors;
EnumDisplayMonitors (0, 0, &enumMonitorsProc, (LPARAM) &monitors);
const double globalDPI = getGlobalDPI();
if (monitors.size() == 0)
monitors.add (MonitorInfo (rectangleFromRECT (getWindowRect (GetDesktopWindow())), true));
monitors.add (MonitorInfo (rectangleFromRECT (getWindowRect (GetDesktopWindow())), true, globalDPI));
// make sure the first in the list is the main monitor
for (int i = 1; i < monitors.size(); ++i)
@@ -3218,15 +3292,22 @@ void Desktop::Displays::findDisplays (float masterScale)
RECT workArea;
SystemParametersInfo (SPI_GETWORKAREA, 0, &workArea, 0);
const double dpi = getDPI(); // (this has only one value for all monitors)
for (int i = 0; i < monitors.size(); ++i)
{
Display d;
d.userArea = d.totalArea = monitors.getReference(i).bounds / masterScale;
d.isMain = monitors.getReference(i).isMain;
d.scale = masterScale;
d.dpi = dpi;
d.dpi = monitors.getReference(i).dpi;
if (d.dpi == 0)
{
d.scale = masterScale;
d.dpi = globalDPI;
}
else
{
d.scale = d.dpi / 96.0;
}
if (d.isMain)
d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea) / masterScale);


+ 1
- 1
source/modules/juce_gui_basics/widgets/juce_Slider.cpp View File

@@ -892,7 +892,7 @@ public:
if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval)
{
dragMode = notDragging;
dragMode = absoluteDrag;
handleAbsoluteDrag (e);
}
else


+ 9
- 2
source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp View File

@@ -23,7 +23,7 @@
*/
CallOutBox::CallOutBox (Component& c, const Rectangle<int>& area, Component* const parent)
: borderSpace (20), arrowSize (16.0f), content (c)
: arrowSize (16.0f), content (c)
{
addAndMakeVisible (content);
@@ -86,10 +86,14 @@ CallOutBox& CallOutBox::launchAsynchronously (Component* content, const Rectangl
void CallOutBox::setArrowSize (const float newSize)
{
arrowSize = newSize;
borderSpace = jmax (20, (int) arrowSize);
refreshPath();
}
int CallOutBox::getBorderSize() const noexcept
{
return jmax (20, (int) arrowSize);
}
void CallOutBox::paint (Graphics& g)
{
getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background);
@@ -97,6 +101,7 @@ void CallOutBox::paint (Graphics& g)
void CallOutBox::resized()
{
const int borderSpace = getBorderSize();
content.setTopLeftPosition (borderSpace, borderSpace);
refreshPath();
}
@@ -168,6 +173,8 @@ void CallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, const R
targetArea = newAreaToPointTo;
availableArea = newAreaToFitIn;
const int borderSpace = getBorderSize();
Rectangle<int> newBounds (content.getWidth() + borderSpace * 2,
content.getHeight() + borderSpace * 2);


+ 2
- 1
source/modules/juce_gui_basics/windows/juce_CallOutBox.h View File

@@ -149,10 +149,11 @@ public:
bool keyPressed (const KeyPress&) override;
/** @internal */
void handleCommandMessage (int) override;
/** @internal */
int getBorderSize() const noexcept;
private:
//==============================================================================
int borderSpace;
float arrowSize;
Component& content;
Path outline;


+ 4
- 4
source/modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp View File

@@ -41,17 +41,17 @@ void WebBrowserComponent::goToURL (const String& url,
{
lastURL = url;
lastHeaders.clear();
if (headers != nullptr)
lastHeaders = *headers;
else
lastHeaders.clear();
lastPostData.setSize (0);
if (postData != nullptr)
lastPostData = *postData;
else
lastPostData.reset();
blankPageShown = false;
}
void WebBrowserComponent::stop()


+ 4
- 4
source/modules/juce_gui_extra/native/juce_linux_WebBrowserComponent.cpp View File

@@ -46,17 +46,17 @@ void WebBrowserComponent::goToURL (const String& url,
{
lastURL = url;
lastHeaders.clear();
if (headers != nullptr)
lastHeaders = *headers;
else
lastHeaders.clear();
lastPostData.setSize (0);
if (postData != nullptr)
lastPostData = *postData;
else
lastPostData.reset();
blankPageShown = false;
}
void WebBrowserComponent::stop()


+ 4
- 2
source/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm View File

@@ -265,13 +265,15 @@ void WebBrowserComponent::goToURL (const String& url,
{
lastURL = url;
lastHeaders.clear();
if (headers != nullptr)
lastHeaders = *headers;
else
lastHeaders.clear();
lastPostData.setSize (0);
if (postData != nullptr)
lastPostData = *postData;
else
lastPostData.reset();
blankPageShown = false;


+ 4
- 2
source/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp View File

@@ -214,13 +214,15 @@ void WebBrowserComponent::goToURL (const String& url,
{
lastURL = url;
lastHeaders.clear();
if (headers != nullptr)
lastHeaders = *headers;
else
lastHeaders.clear();
lastPostData.setSize (0);
if (postData != nullptr)
lastPostData = *postData;
else
lastPostData.reset();
blankPageShown = false;


Loading…
Cancel
Save