Browse Source

Update to new JUCE4

tags/2018-04-16
falkTX 8 years ago
parent
commit
a987743a27
100 changed files with 6592 additions and 1668 deletions
  1. +1
    -0
      .gitignore
  2. +1
    -1
      libs/drowaudio/source/dRowAudio/audio/soundtouch/SoundTouch_Source.cpp
  3. +1
    -1
      libs/drowaudio/source/dRowAudio/audio/soundtouch/cpu_detect_x64_win.cpp
  4. +1
    -1
      libs/drowaudio/source/dRowAudio/utility/dRowAudio_DebugObject.h
  5. +0
    -673
      libs/juce/source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp
  6. +639
    -92
      libs/juce/source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
  7. +0
    -1
      libs/juce/source/modules/juce_audio_basics/juce_audio_basics.cpp
  8. +1
    -1
      libs/juce/source/modules/juce_audio_basics/juce_audio_basics.h
  9. +1
    -1
      libs/juce/source/modules/juce_audio_basics/juce_module_info
  10. +37
    -6
      libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  11. +24
    -4
      libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  12. +288
    -36
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  13. +45
    -2
      libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  14. +1
    -1
      libs/juce/source/modules/juce_audio_devices/juce_module_info
  15. +294
    -18
      libs/juce/source/modules/juce_audio_devices/native/juce_android_Midi.cpp
  16. +218
    -99
      libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  17. +2
    -2
      libs/juce/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  18. +1
    -1
      libs/juce/source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp
  19. +1
    -1
      libs/juce/source/modules/juce_audio_formats/juce_module_info
  20. +9
    -0
      libs/juce/source/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  21. +5
    -7
      libs/juce/source/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  22. +97
    -26
      libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  23. +122
    -54
      libs/juce/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  24. +1
    -1
      libs/juce/source/modules/juce_audio_plugin_client/juce_module_info
  25. +2
    -1
      libs/juce/source/modules/juce_audio_plugin_client/utility/juce_FakeMouseMoveGenerator.h
  26. +1
    -1
      libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  27. +43
    -19
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3Common.h
  28. +47
    -31
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  29. +147
    -104
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  30. +2
    -0
      libs/juce/source/modules/juce_audio_processors/juce_audio_processors.cpp
  31. +6
    -0
      libs/juce/source/modules/juce_audio_processors/juce_audio_processors.h
  32. +3
    -2
      libs/juce/source/modules/juce_audio_processors/juce_module_info
  33. +29
    -2
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  34. +113
    -2
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h
  35. +235
    -54
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
  36. +18
    -7
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
  37. +63
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h
  38. +78
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h
  39. +79
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h
  40. +77
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h
  41. +55
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h
  42. +157
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp
  43. +512
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp
  44. +226
    -0
      libs/juce/source/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h
  45. +38
    -2
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp
  46. +9
    -1
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h
  47. +76
    -0
      libs/juce/source/modules/juce_audio_utils/gui/juce_BluetoothMidiDevicePairingDialogue.h
  48. +17
    -0
      libs/juce/source/modules/juce_audio_utils/juce_audio_utils.cpp
  49. +1
    -0
      libs/juce/source/modules/juce_audio_utils/juce_audio_utils.h
  50. +5
    -2
      libs/juce/source/modules/juce_audio_utils/juce_module_info
  51. +438
    -0
      libs/juce/source/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp
  52. +138
    -0
      libs/juce/source/modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm
  53. +37
    -0
      libs/juce/source/modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp
  54. +36
    -0
      libs/juce/source/modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm
  55. +37
    -0
      libs/juce/source/modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp
  56. +41
    -2
      libs/juce/source/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp
  57. +18
    -4
      libs/juce/source/modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h
  58. +7
    -2
      libs/juce/source/modules/juce_core/containers/juce_Array.h
  59. +35
    -0
      libs/juce/source/modules/juce_core/files/juce_File.cpp
  60. +21
    -15
      libs/juce/source/modules/juce_core/files/juce_File.h
  61. +1
    -1
      libs/juce/source/modules/juce_core/juce_module_info
  62. +2
    -0
      libs/juce/source/modules/juce_core/maths/juce_NormalisableRange.h
  63. +60
    -6
      libs/juce/source/modules/juce_core/memory/juce_ByteOrder.h
  64. +835
    -0
      libs/juce/source/modules/juce_core/native/java/AndroidMidi.java
  65. +81
    -0
      libs/juce/source/modules/juce_core/native/java/AndroidMidiFallback.java
  66. +222
    -72
      libs/juce/source/modules/juce_core/native/java/JuceAppActivity.java
  67. +28
    -133
      libs/juce/source/modules/juce_core/native/juce_android_JNIHelpers.h
  68. +11
    -25
      libs/juce/source/modules/juce_core/native/juce_android_SystemStats.cpp
  69. +232
    -0
      libs/juce/source/modules/juce_core/native/juce_android_Threads.cpp
  70. +1
    -1
      libs/juce/source/modules/juce_core/native/juce_linux_CommonFile.cpp
  71. +1
    -1
      libs/juce/source/modules/juce_core/native/juce_linux_Files.cpp
  72. +7
    -2
      libs/juce/source/modules/juce_core/native/juce_mac_Files.mm
  73. +5
    -18
      libs/juce/source/modules/juce_core/native/juce_posix_SharedCode.h
  74. +34
    -2
      libs/juce/source/modules/juce_core/native/juce_win32_Files.cpp
  75. +6
    -0
      libs/juce/source/modules/juce_core/system/juce_CompilerSupport.h
  76. +35
    -29
      libs/juce/source/modules/juce_core/system/juce_PlatformDefs.h
  77. +3
    -3
      libs/juce/source/modules/juce_core/system/juce_StandardHeader.h
  78. +10
    -0
      libs/juce/source/modules/juce_core/text/juce_CharacterFunctions.cpp
  79. +10
    -0
      libs/juce/source/modules/juce_core/text/juce_CharacterFunctions.h
  80. +152
    -27
      libs/juce/source/modules/juce_core/text/juce_String.cpp
  81. +14
    -0
      libs/juce/source/modules/juce_core/text/juce_String.h
  82. +6
    -0
      libs/juce/source/modules/juce_core/text/juce_StringArray.cpp
  83. +9
    -0
      libs/juce/source/modules/juce_core/text/juce_StringArray.h
  84. +41
    -0
      libs/juce/source/modules/juce_core/unit_tests/juce_UnitTest.h
  85. +1
    -1
      libs/juce/source/modules/juce_cryptography/juce_module_info
  86. +1
    -1
      libs/juce/source/modules/juce_data_structures/juce_module_info
  87. +1
    -1
      libs/juce/source/modules/juce_events/juce_module_info
  88. +2
    -0
      libs/juce/source/modules/juce_events/native/juce_android_Messaging.cpp
  89. +1
    -1
      libs/juce/source/modules/juce_graphics/juce_module_info
  90. +12
    -12
      libs/juce/source/modules/juce_gui_basics/components/juce_Component.cpp
  91. +2
    -2
      libs/juce/source/modules/juce_gui_basics/components/juce_Component.h
  92. +2
    -2
      libs/juce/source/modules/juce_gui_basics/components/juce_Desktop.cpp
  93. +1
    -1
      libs/juce/source/modules/juce_gui_basics/juce_module_info
  94. +9
    -5
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp
  95. +14
    -0
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseEvent.h
  96. +30
    -19
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
  97. +24
    -9
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.h
  98. +17
    -11
      libs/juce/source/modules/juce_gui_basics/native/juce_android_Windowing.cpp
  99. +20
    -3
      libs/juce/source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm
  100. +12
    -0
      libs/juce/source/modules/juce_gui_basics/native/juce_ios_Windowing.mm

+ 1
- 0
.gitignore View File

@@ -52,4 +52,5 @@ libs/juce/source/juce_amalgamated.mm
libs/juce/source/modules/juce_box2d/
libs/juce/source/modules/juce_browser_plugin_client/
libs/juce/source/modules/juce_opengl/
libs/juce/source/modules/juce_osc/
libs/juce/source/modules/juce_video/

+ 1
- 1
libs/drowaudio/source/dRowAudio/audio/soundtouch/SoundTouch_Source.cpp View File

@@ -91,7 +91,7 @@
#include "TDStretch.cpp"
#if JUCE_64BIT
#if JUCE_WIN
#if JUCE_WINDOWS
#include "cpu_detect_x64_win.cpp"
#elif JUCE_MAC || JUCE_IOS || JUCE_LINUX
#include "cpu_detect_x64_gcc.cpp"


+ 1
- 1
libs/drowaudio/source/dRowAudio/audio/soundtouch/cpu_detect_x64_win.cpp View File

@@ -42,7 +42,7 @@
#include "cpu_detect.h"
#ifndef WIN64
#ifndef _WIN64
#error wrong platform - this source code file is exclusively for Win64 platform
#endif


+ 1
- 1
libs/drowaudio/source/dRowAudio/utility/dRowAudio_DebugObject.h View File

@@ -156,7 +156,7 @@ private:
if (xml == nullptr)
return "invalid XmlElement";
return newLine + xml->createDocument (String::empty, false, includeXmlHeader);
return String(NewLine::getDefault()) + xml->createDocument (String::empty, false, includeXmlHeader);
}

String getStringFromValueTree() const


+ 0
- 673
libs/juce/source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.cpp View File

@@ -1,673 +0,0 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2015 - ROLI Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioSampleBuffer::AudioSampleBuffer() noexcept
: numChannels (0), size (0), allocatedBytes (0),
channels (static_cast<float**> (preallocatedChannelSpace)),
isClear (false)
{
}
AudioSampleBuffer::AudioSampleBuffer (const int numChans,
const int numSamples) noexcept
: numChannels (numChans),
size (numSamples)
{
jassert (numSamples >= 0);
jassert (numChans >= 0);
allocateData();
}
AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) noexcept
: numChannels (other.numChannels),
size (other.size),
allocatedBytes (other.allocatedBytes)
{
if (allocatedBytes == 0)
{
allocateChannels (other.channels, 0);
}
else
{
allocateData();
if (other.isClear)
{
clear();
}
else
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
}
}
}
void AudioSampleBuffer::allocateData()
{
const size_t channelListSize = sizeof (float*) * (size_t) (numChannels + 1);
allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (float) + channelListSize + 32;
allocatedData.malloc (allocatedBytes);
channels = reinterpret_cast<float**> (allocatedData.getData());
float* chan = (float*) (allocatedData + channelListSize);
for (int i = 0; i < numChannels; ++i)
{
channels[i] = chan;
chan += size;
}
channels [numChannels] = nullptr;
isClear = false;
}
AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
const int numChans,
const int numSamples) noexcept
: numChannels (numChans),
size (numSamples),
allocatedBytes (0)
{
jassert (dataToReferTo != nullptr);
jassert (numChans >= 0 && numSamples >= 0);
allocateChannels (dataToReferTo, 0);
}
AudioSampleBuffer::AudioSampleBuffer (float* const* dataToReferTo,
const int numChans,
const int startSample,
const int numSamples) noexcept
: numChannels (numChans),
size (numSamples),
allocatedBytes (0),
isClear (false)
{
jassert (dataToReferTo != nullptr);
jassert (numChans >= 0 && startSample >= 0 && numSamples >= 0);
allocateChannels (dataToReferTo, startSample);
}
void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo,
const int newNumChannels,
const int newNumSamples) noexcept
{
jassert (dataToReferTo != nullptr);
jassert (newNumChannels >= 0 && newNumSamples >= 0);
if (allocatedBytes != 0)
{
allocatedBytes = 0;
allocatedData.free();
}
numChannels = newNumChannels;
size = newNumSamples;
allocateChannels (dataToReferTo, 0);
jassert (! isClear);
}
void AudioSampleBuffer::allocateChannels (float* const* const dataToReferTo, int offset)
{
jassert (offset >= 0);
// (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools)
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
{
channels = static_cast<float**> (preallocatedChannelSpace);
}
else
{
allocatedData.malloc ((size_t) numChannels + 1, sizeof (float*));
channels = reinterpret_cast<float**> (allocatedData.getData());
}
for (int i = 0; i < numChannels; ++i)
{
// you have to pass in the same number of valid pointers as numChannels
jassert (dataToReferTo[i] != nullptr);
channels[i] = dataToReferTo[i] + offset;
}
channels [numChannels] = nullptr;
isClear = false;
}
AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) noexcept
{
if (this != &other)
{
setSize (other.getNumChannels(), other.getNumSamples(), false, false, false);
if (other.isClear)
{
clear();
}
else
{
isClear = false;
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::copy (channels[i], other.channels[i], size);
}
}
return *this;
}
AudioSampleBuffer::~AudioSampleBuffer() noexcept
{
}
void AudioSampleBuffer::setSize (const int newNumChannels,
const int newNumSamples,
const bool keepExistingContent,
const bool clearExtraSpace,
const bool avoidReallocating) noexcept
{
jassert (newNumChannels >= 0);
jassert (newNumSamples >= 0);
if (newNumSamples != size || newNumChannels != numChannels)
{
const size_t allocatedSamplesPerChannel = ((size_t) newNumSamples + 3) & ~3u;
const size_t channelListSize = ((sizeof (float*) * (size_t) (newNumChannels + 1)) + 15) & ~15u;
const size_t newTotalBytes = ((size_t) newNumChannels * (size_t) allocatedSamplesPerChannel * sizeof (float))
+ channelListSize + 32;
if (keepExistingContent)
{
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);
for (int j = 0; j < newNumChannels; ++j)
{
newChannels[j] = newChan;
newChan += allocatedSamplesPerChannel;
}
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;
channels = newChannels;
}
else
{
if (avoidReallocating && allocatedBytes >= newTotalBytes)
{
if (clearExtraSpace || isClear)
allocatedData.clear (newTotalBytes);
}
else
{
allocatedBytes = newTotalBytes;
allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear);
channels = reinterpret_cast<float**> (allocatedData.getData());
}
float* chan = reinterpret_cast<float*> (allocatedData + channelListSize);
for (int i = 0; i < newNumChannels; ++i)
{
channels[i] = chan;
chan += allocatedSamplesPerChannel;
}
}
channels [newNumChannels] = 0;
size = newNumSamples;
numChannels = newNumChannels;
}
}
void AudioSampleBuffer::clear() noexcept
{
if (! isClear)
{
for (int i = 0; i < numChannels; ++i)
FloatVectorOperations::clear (channels[i], size);
isClear = true;
}
}
void AudioSampleBuffer::clear (const int startSample,
const int numSamples) noexcept
{
jassert (startSample >= 0 && startSample + numSamples <= size);
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,
const int startSample,
const int numSamples) noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
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,
const int startSample,
int numSamples,
const float gain) noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (gain != 1.0f && ! isClear)
{
float* const d = channels [channel] + startSample;
if (gain == 0.0f)
FloatVectorOperations::clear (d, numSamples);
else
FloatVectorOperations::multiply (d, gain, numSamples);
}
}
void AudioSampleBuffer::applyGainRamp (const int channel,
const int startSample,
int numSamples,
float startGain,
float endGain) noexcept
{
if (! isClear)
{
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;
while (--numSamples >= 0)
{
*d++ *= startGain;
startGain += increment;
}
}
}
}
void AudioSampleBuffer::applyGain (int startSample, int numSamples, float gain) noexcept
{
for (int i = 0; i < numChannels; ++i)
applyGain (i, startSample, numSamples, gain);
}
void AudioSampleBuffer::applyGain (const float gain) noexcept
{
applyGain (0, size, gain);
}
void AudioSampleBuffer::applyGainRamp (int startSample, int numSamples,
float startGain, float endGain) noexcept
{
for (int i = 0; i < numChannels; ++i)
applyGainRamp (i, startSample, numSamples, startGain, endGain);
}
void AudioSampleBuffer::addFrom (const int destChannel,
const int destStartSample,
const AudioSampleBuffer& source,
const int sourceChannel,
const int sourceStartSample,
int numSamples,
const float gain) noexcept
{
jassert (&source != this || sourceChannel != destChannel);
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (isPositiveAndBelow (sourceChannel, source.numChannels));
jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size);
if (gain != 0.0f && numSamples > 0 && ! source.isClear)
{
float* const d = channels [destChannel] + destStartSample;
const float* const s = source.channels [sourceChannel] + sourceStartSample;
if (isClear)
{
isClear = false;
if (gain != 1.0f)
FloatVectorOperations::copyWithMultiply (d, s, gain, numSamples);
else
FloatVectorOperations::copy (d, s, numSamples);
}
else
{
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, s, gain, numSamples);
else
FloatVectorOperations::add (d, s, numSamples);
}
}
}
void AudioSampleBuffer::addFrom (const int destChannel,
const int destStartSample,
const float* source,
int numSamples,
const float gain) noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (source != nullptr);
if (gain != 0.0f && numSamples > 0)
{
float* const d = channels [destChannel] + destStartSample;
if (isClear)
{
isClear = false;
if (gain != 1.0f)
FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples);
else
FloatVectorOperations::copy (d, source, numSamples);
}
else
{
if (gain != 1.0f)
FloatVectorOperations::addWithMultiply (d, source, gain, numSamples);
else
FloatVectorOperations::add (d, source, numSamples);
}
}
}
void AudioSampleBuffer::addFromWithRamp (const int destChannel,
const int destStartSample,
const float* source,
int numSamples,
float startGain,
const float endGain) noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (source != nullptr);
if (startGain == endGain)
{
addFrom (destChannel, destStartSample, source, numSamples, startGain);
}
else
{
if (numSamples > 0 && (startGain != 0.0f || endGain != 0.0f))
{
isClear = false;
const float increment = (endGain - startGain) / numSamples;
float* d = channels [destChannel] + destStartSample;
while (--numSamples >= 0)
{
*d++ += startGain * *source++;
startGain += increment;
}
}
}
}
void AudioSampleBuffer::copyFrom (const int destChannel,
const int destStartSample,
const AudioSampleBuffer& source,
const int sourceChannel,
const int sourceStartSample,
int numSamples) noexcept
{
jassert (&source != this || sourceChannel != destChannel);
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (isPositiveAndBelow (sourceChannel, source.numChannels));
jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size);
if (numSamples > 0)
{
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,
const int destStartSample,
const float* source,
int numSamples) noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (source != nullptr);
if (numSamples > 0)
{
isClear = false;
FloatVectorOperations::copy (channels [destChannel] + destStartSample, source, numSamples);
}
}
void AudioSampleBuffer::copyFrom (const int destChannel,
const int destStartSample,
const float* source,
int numSamples,
const float gain) noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (source != nullptr);
if (numSamples > 0)
{
float* const d = channels [destChannel] + destStartSample;
if (gain != 1.0f)
{
if (gain == 0)
{
if (! isClear)
FloatVectorOperations::clear (d, numSamples);
}
else
{
isClear = false;
FloatVectorOperations::copyWithMultiply (d, source, gain, numSamples);
}
}
else
{
isClear = false;
FloatVectorOperations::copy (d, source, numSamples);
}
}
}
void AudioSampleBuffer::copyFromWithRamp (const int destChannel,
const int destStartSample,
const float* source,
int numSamples,
float startGain,
float endGain) noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (destStartSample >= 0 && destStartSample + numSamples <= size);
jassert (source != nullptr);
if (startGain == endGain)
{
copyFrom (destChannel, destStartSample, source, numSamples, startGain);
}
else
{
if (numSamples > 0 && (startGain != 0.0f || endGain != 0.0f))
{
isClear = false;
const float increment = (endGain - startGain) / numSamples;
float* d = channels [destChannel] + destStartSample;
while (--numSamples >= 0)
{
*d++ = startGain * *source++;
startGain += increment;
}
}
}
}
void AudioSampleBuffer::reverse (int channel, int startSample, int numSamples) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (! isClear)
std::reverse (channels[channel] + startSample,
channels[channel] + startSample + numSamples);
}
void AudioSampleBuffer::reverse (int startSample, int numSamples) const noexcept
{
for (int i = 0; i < numChannels; ++i)
reverse (i, startSample, numSamples);
}
Range<float> AudioSampleBuffer::findMinMax (const int channel,
const int startSample,
int numSamples) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (isClear)
return Range<float>();
return FloatVectorOperations::findMinAndMax (channels [channel] + startSample, numSamples);
}
float AudioSampleBuffer::getMagnitude (const int channel,
const int startSample,
const int numSamples) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (isClear)
return 0.0f;
const Range<float> r (findMinMax (channel, startSample, numSamples));
return jmax (r.getStart(), -r.getStart(), r.getEnd(), -r.getEnd());
}
float AudioSampleBuffer::getMagnitude (int startSample, int numSamples) const noexcept
{
float mag = 0.0f;
if (! isClear)
for (int i = 0; i < numChannels; ++i)
mag = jmax (mag, getMagnitude (i, startSample, numSamples));
return mag;
}
float AudioSampleBuffer::getRMSLevel (const int channel,
const int startSample,
const int numSamples) const noexcept
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && startSample + numSamples <= size);
if (numSamples <= 0 || channel < 0 || channel >= numChannels || isClear)
return 0.0f;
const float* const data = channels [channel] + startSample;
double sum = 0.0;
for (int i = 0; i < numSamples; ++i)
{
const float sample = data [i];
sum += sample * sample;
}
return (float) std::sqrt (sum / numSamples);
}

+ 639
- 92
libs/juce/source/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
File diff suppressed because it is too large
View File


+ 0
- 1
libs/juce/source/modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -80,7 +80,6 @@ namespace juce
{
#include "buffers/juce_AudioDataConverters.cpp"
#include "buffers/juce_AudioSampleBuffer.cpp"
#include "buffers/juce_FloatVectorOperations.cpp"
#include "effects/juce_IIRFilter.cpp"
#include "effects/juce_IIRFilterOld.cpp"


+ 1
- 1
libs/juce/source/modules/juce_audio_basics/juce_audio_basics.h View File

@@ -35,8 +35,8 @@ namespace juce
#undef Factor
#include "buffers/juce_AudioDataConverters.h"
#include "buffers/juce_AudioSampleBuffer.h"
#include "buffers/juce_FloatVectorOperations.h"
#include "buffers/juce_AudioSampleBuffer.h"
#include "effects/juce_Decibels.h"
#include "effects/juce_IIRFilter.h"
#include "effects/juce_IIRFilterOld.h"


+ 1
- 1
libs/juce/source/modules/juce_audio_basics/juce_module_info View File

@@ -1,7 +1,7 @@
{
"id": "juce_audio_basics",
"name": "JUCE audio and midi data classes",
"version": "3.2.0",
"version": "4.0.1",
"description": "Classes for audio buffer manipulation, midi message handling, synthesis, etc",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",


+ 37
- 6
libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -71,6 +71,18 @@ bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const no
return noteOnTime < other.noteOnTime;
}
void SynthesiserVoice::renderNextBlock (AudioBuffer<double>& outputBuffer,
int startSample, int numSamples)
{
AudioBuffer<double> subBuffer (outputBuffer.getArrayOfWritePointers(),
outputBuffer.getNumChannels(),
startSample, numSamples);
tempBuffer.makeCopyOf (subBuffer);
renderNextBlock (tempBuffer, 0, numSamples);
subBuffer.makeCopyOf (tempBuffer);
}
//==============================================================================
Synthesiser::Synthesiser()
: sampleRate (0),
@@ -156,8 +168,11 @@ void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
}
}
void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBuffer& midiData,
int startSample, int numSamples)
template <typename floatType>
void Synthesiser::processNextBlock (AudioBuffer<floatType>& outputAudio,
const MidiBuffer& midiData,
int startSample,
int numSamples)
{
// must set the sample rate before using this!
jassert (sampleRate != 0);
@@ -174,7 +189,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
{
if (! midiIterator.getNextEvent (m, midiEventPos))
{
renderVoices (outputBuffer, startSample, numSamples);
renderVoices (outputAudio, startSample, numSamples);
return;
}
@@ -182,7 +197,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
if (samplesToNextMidiMessage >= numSamples)
{
renderVoices (outputBuffer, startSample, numSamples);
renderVoices (outputAudio, startSample, numSamples);
handleMidiEvent (m);
break;
}
@@ -193,7 +208,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
continue;
}
renderVoices (outputBuffer, startSample, samplesToNextMidiMessage);
renderVoices (outputAudio, startSample, samplesToNextMidiMessage);
handleMidiEvent (m);
startSample += samplesToNextMidiMessage;
numSamples -= samplesToNextMidiMessage;
@@ -203,7 +218,23 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
handleMidiEvent (m);
}
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
// explicit template instantiation
template void Synthesiser::processNextBlock<float> (AudioBuffer<float>& outputAudio,
const MidiBuffer& midiData,
int startSample,
int numSamples);
template void Synthesiser::processNextBlock<double> (AudioBuffer<double>& outputAudio,
const MidiBuffer& midiData,
int startSample,
int numSamples);
void Synthesiser::renderVoices (AudioBuffer<float>& buffer, int startSample, int numSamples)
{
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
}
void Synthesiser::renderVoices (AudioBuffer<double>& buffer, int startSample, int numSamples)
{
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);


+ 24
- 4
libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -182,9 +182,12 @@ public:
involve rendering as little as 1 sample at a time. In between rendering callbacks,
the voice's methods will be called to tell it about note and controller events.
*/
virtual void renderNextBlock (AudioSampleBuffer& outputBuffer,
virtual void renderNextBlock (AudioBuffer<float>& outputBuffer,
int startSample,
int numSamples) = 0;
virtual void renderNextBlock (AudioBuffer<double>& outputBuffer,
int startSample,
int numSamples);
/** Changes the voice's reference sample rate.
@@ -255,6 +258,8 @@ private:
SynthesiserSound::Ptr currentlyPlayingSound;
bool keyIsDown, sustainPedalDown, sostenutoPedalDown;
AudioBuffer<float> tempBuffer;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// Note the new parameters for this method.
virtual int stopNote (bool) { return 0; }
@@ -504,10 +509,17 @@ public:
both to the audio output buffer and the midi input buffer, so any midi events
with timestamps outside the specified region will be ignored.
*/
void renderNextBlock (AudioSampleBuffer& outputAudio,
inline void renderNextBlock (AudioBuffer<float>& outputAudio,
const MidiBuffer& inputMidi,
int startSample,
int numSamples);
int numSamples)
{ processNextBlock (outputAudio, inputMidi, startSample, numSamples); }
inline void renderNextBlock (AudioBuffer<double>& outputAudio,
const MidiBuffer& inputMidi,
int startSample,
int numSamples)
{ processNextBlock (outputAudio, inputMidi, startSample, numSamples); }
/** Returns the current target sample rate at which rendering is being done.
Subclasses may need to know this so that they can pitch things correctly.
@@ -545,7 +557,9 @@ protected:
By default this just calls renderNextBlock() on each voice, but you may need
to override it to handle custom cases.
*/
virtual void renderVoices (AudioSampleBuffer& outputAudio,
virtual void renderVoices (AudioBuffer<float>& outputAudio,
int startSample, int numSamples);
virtual void renderVoices (AudioBuffer<double>& outputAudio,
int startSample, int numSamples);
/** Searches through the voices to find one that's not currently playing, and
@@ -592,6 +606,12 @@ protected:
private:
//==============================================================================
template <typename floatType>
void processNextBlock (AudioBuffer<floatType>& outputAudio,
const MidiBuffer& inputMidi,
int startSample,
int numSamples);
//==============================================================================
double sampleRate;
uint32 lastNoteOnCounter;
int minimumSubBlockSize;


+ 288
- 36
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -93,7 +93,6 @@ AudioDeviceManager::AudioDeviceManager()
numOutputChansNeeded (2),
listNeedsScanning (true),
inputLevel (0),
testSoundPosition (0),
cpuUsageMs (0),
timeToCpuScale (0)
{
@@ -589,8 +588,6 @@ void AudioDeviceManager::stopDevice()
{
if (currentAudioDevice != nullptr)
currentAudioDevice->stop();
testSound = nullptr;
}
void AudioDeviceManager::closeAudioDevice()
@@ -762,20 +759,6 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
for (int i = 0; i < numOutputChannels; ++i)
zeromem (outputChannelData[i], sizeof (float) * (size_t) numSamples);
}
if (testSound != nullptr)
{
const int numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
const float* const src = testSound->getReadPointer (0, testSoundPosition);
for (int i = 0; i < numOutputChannels; ++i)
for (int j = 0; j < numSamps; ++j)
outputChannelData [i][j] += src[j];
testSoundPosition += numSamps;
if (testSoundPosition >= testSound->getNumSamples())
testSound = nullptr;
}
}
void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device)
@@ -944,42 +927,311 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName)
}
//==============================================================================
void AudioDeviceManager::playTestSound()
// This is an AudioTransportSource which will own it's assigned source
class AudioSourceOwningTransportSource : public AudioTransportSource
{
{ // cunningly nested to swap, unlock and delete in that order.
ScopedPointer<AudioSampleBuffer> oldSound;
public:
AudioSourceOwningTransportSource() {}
~AudioSourceOwningTransportSource() { setSource (nullptr); }
void setSource (PositionableAudioSource* newSource)
{
if (src != newSource)
{
const ScopedLock sl (audioCallbackLock);
oldSound = testSound;
ScopedPointer<PositionableAudioSource> oldSourceDeleter (src);
src = newSource;
// tell the base class about the new source before deleting the old one
AudioTransportSource::setSource (newSource);
}
}
testSoundPosition = 0;
private:
ScopedPointer<PositionableAudioSource> src;
if (currentAudioDevice != nullptr)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourceOwningTransportSource)
};
//==============================================================================
// An Audio player which will remove itself from the AudioDeviceManager's
// callback list once it finishes playing its source
class AutoRemovingSourcePlayer : public AudioSourcePlayer,
private ChangeListener
{
public:
struct DeleteOnMessageThread : public CallbackMessage
{
DeleteOnMessageThread (AutoRemovingSourcePlayer* p) : parent (p) {}
void messageCallback() override { delete parent; }
AutoRemovingSourcePlayer* parent;
};
//==============================================================================
AutoRemovingSourcePlayer (AudioDeviceManager& deviceManager, bool ownSource)
: manager (deviceManager),
deleteWhenDone (ownSource),
hasAddedCallback (false),
recursiveEntry (false)
{
}
void changeListenerCallback (ChangeBroadcaster* newSource) override
{
if (AudioTransportSource* currentTransport
= dynamic_cast<AudioTransportSource*> (getCurrentSource()))
{
ignoreUnused (newSource);
jassert (newSource == currentTransport);
if (! currentTransport->isPlaying())
{
// this will call audioDeviceStopped!
manager.removeAudioCallback (this);
}
else if (! hasAddedCallback)
{
hasAddedCallback = true;
manager.addAudioCallback (this);
}
}
}
void audioDeviceStopped() override
{
if (! recursiveEntry)
{
ScopedValueSetter<bool> s (recursiveEntry, true, false);
manager.removeAudioCallback (this);
AudioSourcePlayer::audioDeviceStopped();
if (MessageManager* mm = MessageManager::getInstanceWithoutCreating())
{
if (mm->isThisTheMessageThread())
delete this;
else
(new DeleteOnMessageThread (this))->post();
}
}
}
void setSource (AudioTransportSource* newSource)
{
const double sampleRate = currentAudioDevice->getCurrentSampleRate();
const int soundLength = (int) sampleRate;
AudioSource* oldSource = getCurrentSource();
if (AudioTransportSource* oldTransport = dynamic_cast<AudioTransportSource*> (oldSource))
oldTransport->removeChangeListener (this);
const double frequency = 440.0;
const float amplitude = 0.5f;
if (newSource != nullptr)
newSource->addChangeListener (this);
const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency);
AudioSourcePlayer::setSource (newSource);
AudioSampleBuffer* const newSound = new AudioSampleBuffer (1, soundLength);
if (deleteWhenDone)
delete oldSource;
}
for (int i = 0; i < soundLength; ++i)
newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample));
private:
// only allow myself to be deleted when my audio callback has been removed
~AutoRemovingSourcePlayer()
{
setSource (nullptr);
}
newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
AudioDeviceManager& manager;
bool deleteWhenDone, hasAddedCallback, recursiveEntry;
const ScopedLock sl (audioCallbackLock);
testSound = newSound;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AutoRemovingSourcePlayer)
};
//==============================================================================
// An AudioSource which simply outputs a buffer
class AudioSampleBufferSource : public PositionableAudioSource
{
public:
AudioSampleBufferSource (AudioSampleBuffer* audioBuffer, bool shouldLoop, bool ownBuffer)
: position (0),
buffer (audioBuffer),
looping (shouldLoop),
deleteWhenDone (ownBuffer)
{}
~AudioSampleBufferSource()
{
if (deleteWhenDone)
delete buffer;
}
//==============================================================================
void setNextReadPosition (int64 newPosition) override
{
jassert (newPosition >= 0);
if (looping)
newPosition = newPosition % static_cast<int64> (buffer->getNumSamples());
position = jmin (buffer->getNumSamples(), static_cast<int> (newPosition));
}
int64 getNextReadPosition() const override
{
return static_cast<int64> (position);
}
int64 getTotalLength() const override
{
return static_cast<int64> (buffer->getNumSamples());
}
bool isLooping() const override
{
return looping;
}
void setLooping (bool shouldLoop) override
{
looping = shouldLoop;
}
//==============================================================================
void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override
{
ignoreUnused (samplesPerBlockExpected, sampleRate);
}
void releaseResources() override
{}
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
{
int max = jmin (buffer->getNumSamples() - position, bufferToFill.numSamples);
jassert (max >= 0);
{
int ch;
int maxInChannels = buffer->getNumChannels();
int maxOutChannels = jmin (bufferToFill.buffer->getNumChannels(),
jmax (maxInChannels, 2));
for (ch = 0; ch < maxOutChannels; ch++)
{
int inChannel = ch % maxInChannels;
if (max > 0)
bufferToFill.buffer->copyFrom (ch, bufferToFill.startSample, *buffer, inChannel, position, max);
}
for (; ch < bufferToFill.buffer->getNumChannels(); ++ch)
bufferToFill.buffer->clear (ch, bufferToFill.startSample, bufferToFill.numSamples);
}
position += max;
if (looping)
position = position % buffer->getNumSamples();
}
private:
//==============================================================================
int position;
AudioSampleBuffer* buffer;
bool looping, deleteWhenDone;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSampleBufferSource)
};
void AudioDeviceManager::playSound (const File& file)
{
if (file.existsAsFile())
{
AudioFormatManager formatManager;
formatManager.registerBasicFormats();
playSound (formatManager.createReaderFor (file), true);
}
}
void AudioDeviceManager::playSound (const void* resourceData, size_t resourceSize)
{
if (resourceData != nullptr && resourceSize > 0)
{
AudioFormatManager formatManager;
formatManager.registerBasicFormats();
MemoryInputStream* mem = new MemoryInputStream (resourceData, resourceSize, false);
playSound (formatManager.createReaderFor (mem), true);
}
}
void AudioDeviceManager::playSound (AudioFormatReader* reader, bool deleteWhenFinished)
{
playSound (new AudioFormatReaderSource (reader, deleteWhenFinished), true);
}
void AudioDeviceManager::playSound (PositionableAudioSource* audioSource, bool deleteWhenFinished)
{
if (audioSource != nullptr && currentAudioDevice != nullptr)
{
if (AudioTransportSource* transport = dynamic_cast<AudioTransportSource*> (audioSource))
{
AutoRemovingSourcePlayer* player = new AutoRemovingSourcePlayer (*this, deleteWhenFinished);
player->setSource (transport);
}
else
{
AudioTransportSource* transportSource;
if (deleteWhenFinished)
{
AudioSourceOwningTransportSource* owningTransportSource = new AudioSourceOwningTransportSource();
owningTransportSource->setSource (audioSource);
transportSource = owningTransportSource;
}
else
{
transportSource = new AudioTransportSource;
transportSource->setSource (audioSource);
}
// recursively call myself
playSound (transportSource, true);
transportSource->start();
}
}
else
{
if (deleteWhenFinished)
delete audioSource;
}
}
void AudioDeviceManager::playSound (AudioSampleBuffer* buffer, bool deleteWhenFinished)
{
playSound (new AudioSampleBufferSource (buffer, false, deleteWhenFinished), true);
}
void AudioDeviceManager::playTestSound()
{
const double sampleRate = currentAudioDevice->getCurrentSampleRate();
const int soundLength = (int) sampleRate;
const double frequency = 440.0;
const float amplitude = 0.5f;
const double phasePerSample = double_Pi * 2.0 / (sampleRate / frequency);
AudioSampleBuffer* newSound = new AudioSampleBuffer (1, soundLength);
for (int i = 0; i < soundLength; ++i)
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);
playSound (newSound, true);
}
//==============================================================================
void AudioDeviceManager::enableInputLevelMeasurement (const bool enableMeasurement)
{
if (enableMeasurement)


+ 45
- 2
libs/juce/source/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h View File

@@ -404,6 +404,51 @@ public:
*/
void playTestSound();
/** Plays a sound from a file. */
void playSound (const File& file);
/** Convenient method to play sound from a JUCE resource. */
void playSound (const void* resourceData, size_t resourceSize);
/** Plays the sound from an audio format reader.
If deleteWhenFinished is true then the format reader will be
automatically deleted once the sound has finished playing.
*/
void playSound (AudioFormatReader* buffer, bool deleteWhenFinished = false);
/** Plays the sound from a positionable audio source.
This will output the sound coming from a positionable audio source.
This gives you slightly more control over the sound playback compared
to the other playSound methods. For example, if you would like to
stop the sound prematurely you can call this method with a
TransportAudioSource and then call audioSource->stop. Note that,
you must call audioSource->start to start the playback, if your
audioSource is a TransportAudioSource.
The audio device manager will not hold any references to this audio
source once the audio source has stopped playing for any reason,
for example when the sound has finished playing or when you have
called audioSource->stop. Therefore, calling audioSource->start() on
a finished audioSource will not restart the sound again. If this is
desired simply call playSound with the same audioSource again.
@param audioSource the audio source to play
@param deleteWhenFinished If this is true then the audio source will
be deleted once the device manager has finished playing.
*/
void playSound (PositionableAudioSource* audioSource, bool deleteWhenFinished = false);
/** Plays the sound from an audio sample buffer.
This will output the sound contained in an audio sample buffer. If
deleteWhenFinished is true then the audio sample buffer will be
automatically deleted once the sound has finished playing.
*/
void playSound (AudioSampleBuffer* buffer, bool deleteWhenFinished = false);
//==============================================================================
/** Turns on level-measuring.
When enabled, the device manager will measure the peak input level
@@ -452,8 +497,6 @@ private:
mutable bool listNeedsScanning;
Atomic<int> inputLevelMeasurementEnabledCount;
double inputLevel;
ScopedPointer<AudioSampleBuffer> testSound;
int testSoundPosition;
AudioSampleBuffer tempBuffer;
struct MidiCallbackInfo


+ 1
- 1
libs/juce/source/modules/juce_audio_devices/juce_module_info View File

@@ -1,7 +1,7 @@
{
"id": "juce_audio_devices",
"name": "JUCE audio and midi I/O device classes",
"version": "3.2.0",
"version": "4.0.1",
"description": "Classes to play and record from audio and midi i/o devices.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",


+ 294
- 18
libs/juce/source/modules/juce_audio_devices/native/juce_android_Midi.cpp View File

@@ -22,11 +22,228 @@
==============================================================================
*/
StringArray MidiOutput::getDevices()
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getJuceAndroidMidiInputDevices, "getJuceAndroidMidiInputDevices", "()[Ljava/lang/String;") \
METHOD (getJuceAndroidMidiOutputDevices, "getJuceAndroidMidiOutputDevices", "()[Ljava/lang/String;") \
METHOD (openMidiInputPortWithJuceIndex, "openMidiInputPortWithJuceIndex", "(IJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$JuceMidiPort;") \
METHOD (openMidiOutputPortWithJuceIndex, "openMidiOutputPortWithJuceIndex", "(I)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$JuceMidiPort;") \
METHOD (getInputPortNameForJuceIndex, "getInputPortNameForJuceIndex", "(I)Ljava/lang/String;") \
METHOD (getOutputPortNameForJuceIndex, "getOutputPortNameForJuceIndex", "(I)Ljava/lang/String;")
DECLARE_JNI_CLASS (MidiDeviceManager, JUCE_ANDROID_ACTIVITY_CLASSPATH "$MidiDeviceManager")
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (start, "start", "()V" )\
METHOD (stop, "stop", "()V") \
METHOD (close, "close", "()V") \
METHOD (sendMidi, "sendMidi", "([BII)V")
DECLARE_JNI_CLASS (JuceMidiPort, JUCE_ANDROID_ACTIVITY_CLASSPATH "$JuceMidiPort")
#undef JNI_CLASS_MEMBERS
//==============================================================================
class AndroidMidiInput
{
public:
AndroidMidiInput (MidiInput* midiInput, int portIdx,
juce::MidiInputCallback* midiInputCallback, jobject deviceManager)
: juceMidiInput (midiInput),
callback (midiInputCallback),
midiConcatenator (2048),
javaMidiDevice (getEnv()->CallObjectMethod (deviceManager,
MidiDeviceManager.openMidiInputPortWithJuceIndex,
(jint) portIdx,
(jlong) this))
{
}
~AndroidMidiInput()
{
if (jobject d = javaMidiDevice.get())
{
getEnv()->CallVoidMethod (d, JuceMidiPort.close);
javaMidiDevice.clear();
}
}
bool isOpen() const noexcept
{
return javaMidiDevice != nullptr;
}
void start()
{
if (jobject d = javaMidiDevice.get())
getEnv()->CallVoidMethod (d, JuceMidiPort.start);
}
void stop()
{
if (jobject d = javaMidiDevice.get())
getEnv()->CallVoidMethod (d, JuceMidiPort.stop);
callback = nullptr;
}
void receive (jbyteArray byteArray, jlong offset, jint len, jlong timestamp)
{
jassert (byteArray != nullptr);
jbyte* data = getEnv()->GetByteArrayElements (byteArray, nullptr);
HeapBlock<uint8> buffer (len);
std::memcpy (buffer.getData(), data + offset, len);
midiConcatenator.pushMidiData (buffer.getData(),
len, static_cast<double> (timestamp) * 1.0e-9,
juceMidiInput, *callback);
getEnv()->ReleaseByteArrayElements (byteArray, data, 0);
}
private:
MidiInput* juceMidiInput;
MidiInputCallback* callback;
GlobalRef javaMidiDevice;
MidiDataConcatenator midiConcatenator;
};
//==============================================================================
class AndroidMidiOutput
{
StringArray devices;
public:
AndroidMidiOutput (jobject midiDevice)
: javaMidiDevice (midiDevice)
{
}
~AndroidMidiOutput()
{
if (jobject d = javaMidiDevice.get())
{
getEnv()->CallVoidMethod (d, JuceMidiPort.close);
javaMidiDevice.clear();
}
}
void send (jbyteArray byteArray, jint offset, jint len)
{
if (jobject d = javaMidiDevice.get())
getEnv()->CallVoidMethod (d,
JuceMidiPort.sendMidi,
byteArray, offset, len);
}
private:
GlobalRef javaMidiDevice;
};
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024JuceMidiInputPort), handleReceive,
void, (JNIEnv* env, jobject device, jlong host, jbyteArray byteArray,
jint offset, jint count, jlong timestamp))
{
// Java may create a Midi thread which JUCE doesn't know about and this callback may be
// received on this thread. Java will have already created a JNI Env for this new thread,
// which we need to tell Juce about
setEnv (env);
reinterpret_cast<AndroidMidiInput*> (host)->receive (byteArray, offset, count, timestamp);
}
//==============================================================================
class AndroidMidiDeviceManager
{
public:
AndroidMidiDeviceManager ()
: deviceManager (android.activity.callObjectMethod (JuceAppActivity.getAndroidMidiDeviceManager))
{
}
String getInputPortNameForJuceIndex (int idx)
{
if (jobject dm = deviceManager.get())
{
LocalRef<jstring> string ((jstring) getEnv()->CallObjectMethod (dm, MidiDeviceManager.getInputPortNameForJuceIndex, idx));
return juceString (string);
}
return String();
}
String getOutputPortNameForJuceIndex (int idx)
{
if (jobject dm = deviceManager.get())
{
LocalRef<jstring> string ((jstring) getEnv()->CallObjectMethod (dm, MidiDeviceManager.getOutputPortNameForJuceIndex, idx));
return juceString (string);
}
return String();
}
StringArray getDevices (bool input)
{
if (jobject dm = deviceManager.get())
{
jobjectArray jDevices
= (jobjectArray) getEnv()->CallObjectMethod (dm, input ? MidiDeviceManager.getJuceAndroidMidiInputDevices
: MidiDeviceManager.getJuceAndroidMidiOutputDevices);
// Create a local reference as converting this
// to a JUCE string will call into JNI
LocalRef<jobjectArray> devices (jDevices);
return javaStringArrayToJuce (devices);
}
return StringArray();
}
AndroidMidiInput* openMidiInputPortWithIndex (int idx, MidiInput* juceMidiInput, juce::MidiInputCallback* callback)
{
if (jobject dm = deviceManager.get())
{
ScopedPointer<AndroidMidiInput> androidMidiInput (new AndroidMidiInput (juceMidiInput, idx, callback, dm));
if (androidMidiInput->isOpen())
return androidMidiInput.release();
}
return nullptr;
}
AndroidMidiOutput* openMidiOutputPortWithIndex (int idx)
{
if (jobject dm = deviceManager.get())
if (jobject javaMidiPort = getEnv()->CallObjectMethod (dm, MidiDeviceManager.openMidiOutputPortWithJuceIndex, (jint) idx))
return new AndroidMidiOutput (javaMidiPort);
return devices;
return nullptr;
}
private:
static StringArray javaStringArrayToJuce (jobjectArray jStrings)
{
StringArray retval;
JNIEnv* env = getEnv();
const int count = env->GetArrayLength (jStrings);
for (int i = 0; i < count; ++i)
{
LocalRef<jstring> string ((jstring) env->GetObjectArrayElement (jStrings, i));
retval.add (juceString (string));
}
return retval;
}
GlobalRef deviceManager;
};
//==============================================================================
StringArray MidiOutput::getDevices()
{
AndroidMidiDeviceManager manager;
return manager.getDevices (false);
}
int MidiOutput::getDefaultDeviceIndex()
@@ -36,50 +253,109 @@ int MidiOutput::getDefaultDeviceIndex()
MidiOutput* MidiOutput::openDevice (int index)
{
if (index < 0)
return nullptr;
AndroidMidiDeviceManager manager;
String midiOutputName = manager.getOutputPortNameForJuceIndex (index);
if (midiOutputName.isEmpty())
{
// you supplied an invalid device index!
jassertfalse;
return nullptr;
}
if (AndroidMidiOutput* midiOutput = manager.openMidiOutputPortWithIndex (index))
{
MidiOutput* retval = new MidiOutput (midiOutputName);
retval->internal = midiOutput;
return retval;
}
return nullptr;
}
MidiOutput::~MidiOutput()
{
stopBackgroundThread();
delete reinterpret_cast<AndroidMidiOutput*> (internal);
}
void MidiOutput::sendMessageNow (const MidiMessage&)
void MidiOutput::sendMessageNow (const MidiMessage& message)
{
if (AndroidMidiOutput* androidMidi = reinterpret_cast<AndroidMidiOutput*>(internal))
{
JNIEnv* env = getEnv();
const int messageSize = message.getRawDataSize();
LocalRef<jbyteArray> messageContent = LocalRef<jbyteArray> (env->NewByteArray (messageSize));
jbyteArray content = messageContent.get();
jbyte* rawBytes = env->GetByteArrayElements (content, nullptr);
std::memcpy (rawBytes, message.getRawData(), messageSize);
env->ReleaseByteArrayElements (content, rawBytes, 0);
androidMidi->send (content, (jint) 0, (jint) messageSize);
}
}
//==============================================================================
MidiInput::MidiInput (const String& name_)
: name (name_),
internal (0)
MidiInput::MidiInput (const String& nm) : name (nm)
{
}
MidiInput::~MidiInput()
StringArray MidiInput::getDevices()
{
AndroidMidiDeviceManager manager;
return manager.getDevices (true);
}
void MidiInput::start()
int MidiInput::getDefaultDeviceIndex()
{
return 0;
}
void MidiInput::stop()
MidiInput* MidiInput::openDevice (int index, juce::MidiInputCallback* callback)
{
if (index < 0)
return nullptr;
AndroidMidiDeviceManager manager;
String midiInputName = manager.getInputPortNameForJuceIndex (index);
if (midiInputName.isEmpty())
{
// you supplied an invalid device index!
jassertfalse;
return nullptr;
}
ScopedPointer<MidiInput> midiInput (new MidiInput (midiInputName));
midiInput->internal = manager.openMidiInputPortWithIndex (index, midiInput, callback);
return midiInput->internal != nullptr ? midiInput.release()
: nullptr;
}
int MidiInput::getDefaultDeviceIndex()
void MidiInput::start()
{
return 0;
if (AndroidMidiInput* mi = reinterpret_cast<AndroidMidiInput*> (internal))
mi->start();
}
StringArray MidiInput::getDevices()
void MidiInput::stop()
{
StringArray devs;
return devs;
if (AndroidMidiInput* mi = reinterpret_cast<AndroidMidiInput*> (internal))
mi->stop();
}
MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
MidiInput::~MidiInput()
{
return nullptr;
delete reinterpret_cast<AndroidMidiInput*> (internal);
}

+ 218
- 99
libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp View File

@@ -32,7 +32,7 @@ bool isOpenSLAvailable()
//==============================================================================
class OpenSLAudioIODevice : public AudioIODevice,
public Thread
private Thread
{
public:
OpenSLAudioIODevice (const String& deviceName)
@@ -81,13 +81,28 @@ public:
Array<double> getAvailableSampleRates() override
{
static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
return Array<double> (rates, numElementsInArray (rates));
Array<double> retval (rates, numElementsInArray (rates));
// make sure the native sample rate is pafrt of the list
double native = getNativeSampleRate();
if (native != 0.0 && ! retval.contains (native))
retval.add (native);
return retval;
}
Array<int> getAvailableBufferSizes() override
{
static const int sizes[] = { 256, 512, 768, 1024, 1280, 1600 }; // must all be multiples of the block size
return Array<int> (sizes, numElementsInArray (sizes));
// we need to offer the lowest possible buffer size which
// is the native buffer size
const int defaultNumMultiples = 8;
const int nativeBufferSize = getNativeBufferSize();
Array<int> retval;
for (int i = 1; i < defaultNumMultiples; ++i)
retval.add (i * nativeBufferSize);
return retval;
}
String open (const BigInteger& inputChannels,
@@ -116,8 +131,28 @@ public:
outputBuffer.setSize (jmax (1, numOutputChannels), actualBufferSize);
outputBuffer.clear();
recorder = engine.createRecorder (numInputChannels, sampleRate);
player = engine.createPlayer (numOutputChannels, sampleRate);
const int audioBuffersToEnqueue = hasLowLatencyAudioPath ? buffersToEnqueueForLowLatency
: buffersToEnqueueSlowAudio;
DBG ("OpenSL: numInputChannels = " << numInputChannels
<< ", numOutputChannels = " << numOutputChannels
<< ", nativeBufferSize = " << getNativeBufferSize()
<< ", nativeSampleRate = " << getNativeSampleRate()
<< ", actualBufferSize = " << actualBufferSize
<< ", audioBuffersToEnqueue = " << audioBuffersToEnqueue
<< ", sampleRate = " << sampleRate);
if (numInputChannels > 0)
recorder = engine.createRecorder (numInputChannels, sampleRate,
audioBuffersToEnqueue, actualBufferSize);
if (numOutputChannels > 0)
player = engine.createPlayer (numOutputChannels, sampleRate,
audioBuffersToEnqueue, actualBufferSize);
// pre-fill buffers
for (int i = 0; i < audioBuffersToEnqueue; ++i)
processBuffers();
startThread (8);
@@ -134,18 +169,30 @@ public:
player = nullptr;
}
int getDefaultBufferSize() override { return 1024; }
int getOutputLatencyInSamples() override { return outputLatency; }
int getInputLatencyInSamples() override { return inputLatency; }
bool isOpen() override { return deviceOpen; }
int getCurrentBufferSizeSamples() override { return actualBufferSize; }
int getCurrentBitDepth() override { return 16; }
double getCurrentSampleRate() override { return sampleRate; }
BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
BigInteger getActiveInputChannels() const override { return activeInputChans; }
String getLastError() override { return lastError; }
bool isPlaying() override { return callback != nullptr; }
int getDefaultBufferSize() override
{
// Only on a Pro-Audio device will we set the lowest possible buffer size
// by default. We need to be more conservative on other devices
// as they may be low-latency, but still have a crappy CPU.
return (isProAudioDevice() ? 1 : 6)
* defaultBufferSizeIsMultipleOfNative * getNativeBufferSize();
}
double getCurrentSampleRate() override
{
return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate);
}
void start (AudioIODeviceCallback* newCallback) override
{
stop();
@@ -184,6 +231,55 @@ private:
struct Player;
struct Recorder;
enum
{
// The number of buffers to enqueue needs to be at least two for the audio to use the low-latency
// audio path (see "Performance" section in ndk/docs/Additional_library_docs/opensles/index.html)
buffersToEnqueueForLowLatency = 2,
buffersToEnqueueSlowAudio = 4,
defaultBufferSizeIsMultipleOfNative = 1
};
//==================================================================================================
static String audioManagerGetProperty (const String& property)
{
const LocalRef<jstring> jProperty (javaString (property));
const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
jProperty.get()));
if (text.get() != 0)
return juceString (text);
return String();
}
static bool androidHasSystemFeature (const String& property)
{
const LocalRef<jstring> jProperty (javaString (property));
return android.activity.callBooleanMethod (JuceAppActivity.hasSystemFeature, jProperty.get());
}
static double getNativeSampleRate()
{
return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue();
}
static int getNativeBufferSize()
{
const int val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue();
return val > 0 ? val : 512;
}
static bool isProAudioDevice()
{
return androidHasSystemFeature ("android.hardware.audio.pro");
}
static bool hasLowLatencyAudioPath()
{
return androidHasSystemFeature ("android.hardware.audio.low_latency");
}
//==================================================================================================
AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
{
const ScopedLock sl (callbackLock);
@@ -192,29 +288,45 @@ private:
return oldCallback;
}
void run() override
void processBuffers()
{
if (recorder != nullptr) recorder->start();
if (player != nullptr) player->start();
if (recorder != nullptr)
recorder->readNextBlock (inputBuffer, *this);
while (! threadShouldExit())
{
if (player != nullptr) player->writeBuffer (outputBuffer, *this);
if (recorder != nullptr) recorder->readNextBlock (inputBuffer, *this);
const ScopedLock sl (callbackLock);
if (callback != nullptr)
{
callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
actualBufferSize);
}
else
{
outputBuffer.clear();
}
}
if (player != nullptr)
player->writeBuffer (outputBuffer, *this);
}
void run() override
{
setThreadToAudioPriority ();
if (recorder != nullptr) recorder->start();
if (player != nullptr) player->start();
while (! threadShouldExit())
processBuffers();
}
void setThreadToAudioPriority ()
{
// see android.os.Process.THREAD_PRIORITY_AUDIO
const int THREAD_PRIORITY_AUDIO = -16;
jint priority = THREAD_PRIORITY_AUDIO;
if (priority != android.activity.callIntMethod (JuceAppActivity.setCurrentThreadPriority, (jint) priority))
DBG ("Unable to set audio thread priority: priority is still " << priority);
}
//==================================================================================================
@@ -225,7 +337,8 @@ private:
{
if (library.open ("libOpenSLES.so"))
{
typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32, const SLInterfaceID*, const SLboolean*);
typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*,
SLuint32, const SLInterfaceID*, const SLboolean*);
if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
{
@@ -252,21 +365,21 @@ private:
if (engineObject != nullptr) (*engineObject)->Destroy (engineObject);
}
Player* createPlayer (const int numChannels, const int sampleRate)
Player* createPlayer (const int numChannels, const int sampleRate, const int numBuffers, const int bufferSize)
{
if (numChannels <= 0)
return nullptr;