Browse Source

Merge remote-tracking branch 'j/develop'

Conflicts:
	examples/SimpleFFTExample/SimpleFFTExample.jucer
	modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp
	modules/juce_gui_basics/misc/juce_JUCESplashScreen.cpp
	modules/juce_gui_basics/misc/juce_JUCESplashScreen.h
pull/8/head
falkTX 8 years ago
parent
commit
43c0b55b07
100 changed files with 2486 additions and 1482 deletions
  1. +358
    -303
      BREAKING-CHANGES.txt
  2. +64
    -50
      ChangeList.txt
  3. +1
    -1
      examples/AUv3Synth/AUv3Synth.jucer
  4. +4
    -0
      examples/AUv3Synth/JuceLibraryCode/AppConfig.h
  5. +6
    -9
      examples/AUv3Synth/Source/AUv3SynthProcessor.cpp
  6. +1
    -1
      examples/AnimationAppExample/AnimationAppExample.jucer
  7. +1
    -1
      examples/AudioAppExample/AudioAppExample.jucer
  8. +1
    -1
      examples/BLOCKS/BlocksDrawing/BlocksDrawing.jucer
  9. +1
    -1
      examples/BLOCKS/BlocksMonitor/BlocksMonitor.jucer
  10. +1
    -1
      examples/BLOCKS/BlocksSynth/BlocksSynth.jucer
  11. +1
    -1
      examples/BouncingBallWavetableDemo/BouncingBallWavetableDemo.jucer
  12. +1
    -1
      examples/ComponentTutorialExample/ComponentTutorialExample.jucer
  13. +2
    -2
      examples/DSP module plugin demo/DSP module plugin demo.jucer
  14. +8
    -0
      examples/DSP module plugin demo/JuceLibraryCode/AppConfig.h
  15. +22
    -2
      examples/DSP module plugin demo/Source/PluginEditor.cpp
  16. +2
    -2
      examples/DSP module plugin demo/Source/PluginEditor.h
  17. +40
    -10
      examples/DSP module plugin demo/Source/PluginProcessor.cpp
  18. +4
    -0
      examples/DSP module plugin demo/Source/PluginProcessor.h
  19. +1
    -1
      examples/DSPDemo/DSPDemo.jucer
  20. +4
    -0
      examples/DSPDemo/JuceLibraryCode/AppConfig.h
  21. +3
    -3
      examples/DSPDemo/JuceLibraryCode/BinaryData.cpp
  22. +1
    -1
      examples/DSPDemo/JuceLibraryCode/BinaryData.h
  23. +2
    -2
      examples/DSPDemo/Source/Demos/ConvolutionDemo.cpp
  24. +209
    -103
      examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java
  25. +1
    -1
      examples/Demo/JuceDemo.jucer
  26. +4
    -0
      examples/Demo/Source/Demos/GridDemo.cpp
  27. +1
    -1
      examples/Demo/Source/Demos/VideoDemo.cpp
  28. +47
    -25
      examples/Demo/Source/Demos/WidgetsDemo.cpp
  29. +1
    -1
      examples/HelloWorld/HelloWorld.jucer
  30. +1
    -1
      examples/InAppPurchase/Builds/Android/app/CMakeLists.txt
  31. +209
    -103
      examples/InAppPurchase/Builds/Android/app/src/main/java/com/roli/juceinapppurchasesample/InAppPurchase.java
  32. +2
    -0
      examples/InAppPurchase/Builds/iOS/InAppPurchase.xcodeproj/project.pbxproj
  33. +1
    -1
      examples/InAppPurchase/InAppPurchase.jucer
  34. +1
    -1
      examples/MPETest/MPETest.jucer
  35. +209
    -103
      examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java
  36. +1
    -1
      examples/MidiTest/MidiTest.jucer
  37. +209
    -103
      examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java
  38. +1
    -1
      examples/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer
  39. +1
    -1
      examples/OSCMonitor/OSCMonitor.jucer
  40. +2
    -3
      examples/OSCMonitor/Source/OSCLogListBox.h
  41. +209
    -103
      examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java
  42. +1
    -1
      examples/OSCReceiver/OSCReceiver.jucer
  43. +209
    -103
      examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java
  44. +1
    -1
      examples/OSCSender/OSCSender.jucer
  45. +1
    -1
      examples/OpenGLAppExample/OpenGLAppExample.jucer
  46. +1
    -1
      examples/PluckedStringsDemo/PluckedStringsDemo.jucer
  47. +1
    -1
      examples/PlugInSamples/Arpeggiator/Arpeggiator.jucer
  48. +4
    -0
      examples/PlugInSamples/Arpeggiator/JuceLibraryCode/AppConfig.h
  49. +1
    -1
      examples/PlugInSamples/GainPlugIn/GainPlugIn.jucer
  50. +4
    -0
      examples/PlugInSamples/GainPlugIn/JuceLibraryCode/AppConfig.h
  51. +1
    -1
      examples/PlugInSamples/InterAppAudioEffect/InterAppAudioEffect.jucer
  52. +4
    -0
      examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/AppConfig.h
  53. +4
    -0
      examples/PlugInSamples/MultiOutSynth/JuceLibraryCode/AppConfig.h
  54. +1
    -1
      examples/PlugInSamples/MultiOutSynth/MultiOutSynth.jucer
  55. +4
    -0
      examples/PlugInSamples/NoiseGate/JuceLibraryCode/AppConfig.h
  56. +1
    -1
      examples/PlugInSamples/NoiseGate/NoiseGate.jucer
  57. +4
    -0
      examples/PlugInSamples/Surround/JuceLibraryCode/AppConfig.h
  58. +1
    -1
      examples/PlugInSamples/Surround/Surround.jucer
  59. +4
    -0
      examples/SimpleFFTExample/JuceLibraryCode/AppConfig.h
  60. +1
    -1
      examples/SimpleFFTExample/SimpleFFTExample.jucer
  61. +209
    -103
      examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java
  62. +2
    -0
      examples/audio plugin demo/Builds/iOS/Info-AUv3_AppExtension.plist
  63. +2
    -0
      examples/audio plugin demo/Builds/iOS/Info-Standalone_Plugin.plist
  64. +2
    -2
      examples/audio plugin demo/JuceDemoPlugin.jucer
  65. +4
    -0
      examples/audio plugin demo/JuceLibraryCode/AppConfig.h
  66. +2
    -8
      examples/audio plugin demo/Source/PluginEditor.cpp
  67. +1
    -127
      examples/audio plugin demo/Source/PluginProcessor.cpp
  68. +1
    -1
      examples/audio plugin host/Plugin Host.jucer
  69. +6
    -1
      examples/audio plugin host/Source/MainHostWindow.cpp
  70. +1
    -1
      extras/AudioPerformanceTest/AudioPerformanceTest.jucer
  71. +209
    -103
      extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java
  72. +2
    -2
      extras/Projucer/Builds/LinuxMakefile/Makefile
  73. +2
    -2
      extras/Projucer/Builds/MacOSX/Info-App.plist
  74. +4
    -4
      extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj
  75. +2
    -2
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj
  76. +3
    -3
      extras/Projucer/Builds/VisualStudio2013/resources.rc
  77. +2
    -2
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj
  78. +3
    -3
      extras/Projucer/Builds/VisualStudio2015/resources.rc
  79. +2
    -2
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
  80. +3
    -3
      extras/Projucer/Builds/VisualStudio2017/resources.rc
  81. +4
    -3
      extras/Projucer/JuceLibraryCode/BinaryData.cpp
  82. +1
    -1
      extras/Projucer/JuceLibraryCode/BinaryData.h
  83. +2
    -2
      extras/Projucer/JuceLibraryCode/JuceHeader.h
  84. +1
    -1
      extras/Projucer/Projucer.jucer
  85. +3
    -2
      extras/Projucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp
  86. +3
    -0
      extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h
  87. +3
    -5
      extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h
  88. +3
    -0
      extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h
  89. +4
    -0
      extras/UnitTestRunner/JuceLibraryCode/AppConfig.h
  90. +1
    -1
      extras/UnitTestRunner/UnitTestRunner.jucer
  91. +1
    -1
      extras/binarybuilder/BinaryBuilder.jucer
  92. +1
    -1
      extras/windows dll/jucedll.jucer
  93. +17
    -14
      modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h
  94. +5
    -0
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp
  95. +4
    -2
      modules/juce_audio_basics/buffers/juce_AudioChannelSet.h
  96. +7
    -2
      modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp
  97. +4
    -2
      modules/juce_audio_basics/buffers/juce_AudioDataConverters.h
  98. +30
    -11
      modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h
  99. +10
    -5
      modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  100. +34
    -1
      modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h

+ 358
- 303
BREAKING-CHANGES.txt View File

@@ -1,303 +1,358 @@
JUCE breaking changes
=====================

Develop Branch
=============

Change
------
The String (bool) constructor and operator<< (String&, bool) have been
explicitly deleted.

Possible Issues
---------------
Previous code which relied on an implicit bool to int type conversion to
produce a String will not compile.

Workaround
----------
Cast your bool to an integer to generate a string representation of it.

Rationale
---------
Letting things implicitly convert to bool to produce a String opens the door to
all kinds of nasty type conversion edge cases. Furthermore, before this change,
MacOS would automatically convert bools to ints but this wouldn't occur on
different platform. Now the behaviour is consistent across all operating
systems supported by JUCE.


Change
------
The writeAsJSON virtual method of the DynamicObject class requires an
additional parameter, maximumDecimalPlaces, to specify the maximum precision of
floating point numbers.

Possible Issues
---------------
Classes which inherit from DynamicObject and override this method will need to
update their method signature.

Workaround
----------
Your custom DynamicObject class can choose to ignore the additional parameter
if you don't wish to support this behaviour.

Rationale
---------
When serialising the results of calculations to JSON the rounding of floating
point numbers can result in numbers with 17 significant figures where only a
few are required. This change to DynamicObject is required to support
truncating those numbers.



Version 5.1.0
=============

Change
------
The option to set the C++ language standard is now located in the project
settings instead of the build configuration settings.

Possible Issues
---------------
Projects that had a specific verison of the C++ language standard set for
exporter build configurations will instead use the default (C++11) when
re-saving with the new Projucer.

Workaround
----------
Change the "C++ Language Standard" setting in the main project settings to the
required version - the Projucer will add this value to the exported project as
a compiler flag when saving exporters.

Rationale
---------
Having a different C++ language standard option for each build configuration
was unnecessary and was not fully implemented for all exporters. Changing it to
a per-project settings means that the preference will propagate to all
exporters and only needs to be set in one place.


Change
------
PopupMenus now scale according to the AffineTransform and scaling factor of
their target components.

Possible Issues
---------------
Developers who have manually scaled their PopupMenus to fit the scaling factor
of the parent UI will now have the scaling applied two times in a row.

Workaround
----------
1. Do not apply your own manual scaling to make your popups match the UI
scaling

or

2. Override the Look&Feel method
PopupMenu::LookAndFeelMethods::shouldPopupMenuScaleWithTargetComponent and
return false. See
https://github.com/WeAreROLI/JUCE/blob/c288c94c2914af20f36c03ca9c5401fcb555e4e9/modules/juce_gui_basics/menus/juce_PopupMenu.h#725

Rationale
---------
Previously, PopupMenus would not scale if the GUI of the target component (or
any of it’s parents) were scaled. The only way to scale PopupMenus was via the
global scaling factor. This had several drawbacks as the global scaling factor
would scale everything. This was especially problematic in plug-in editors.


Change
------
Removed the setSecurityFlags() method from the Windows implementation of
WebInputStream as it disabled HTTPS security features.

Possible Issues
---------------
Any code previously relying on connections to insecure webpages succeeding will
no longer work.

Workaround
----------
Check network connectivity on Windows and re-write any code that relied on
insecure connections.

Rationale
---------
The previous behaviour resulted in network connections on Windows having all
the HTTPS security features disabled, exposing users to network attacks. HTTPS
connections on Windows are now secure and will fail when connecting to an
insecure web address.


Change
------
Pointer arithmetic on a pointer will have the same result regardless if it is
wrapped in JUCE's Atomic class or not.

Possible Issues
---------------
Any code using pointer arithmetic on Atomic<T*> will now have a different
result leading to undefined behaviour or crashes.

Workaround
----------
Re-write your code in a way that it does not depend on your pointer being
wrapped in JUCE's Atomic or not. See rationale.

Rationale
---------
Before this change, pointer arithmetic with JUCE's Atomic type would yield
confusing results. For example, the following code would assert before this
change:

int* a; Atomic<int*> b;

jassert (++a == ++b);

Pointer a in the above code would be advanced by sizeof(int) whereas the JUCE's
Atomic always advances it's underlying pointer by a single byte. The same is
true for operator+=/operator-= and operator--. The difference in behaviour is
confusing and unintuitive. Furthermore, this aligns JUCE's Atomic type with
std::atomic.



Version 4.3.1
=============

Change
------
JUCE has changed the way native VST3/AudioUnit parameter ids are calculated.

Possible Issues
---------------
DAW projects with automation data written by an AudioUnit or VST3 plug-in built
with pre JUCE 4.3.1 versions will load incorrectly when opened by an AudioUnit
or VST3 built with JUCE versions 4.3.1 and later. Plug-ins using
JUCE_FORCE_USE_LEGACY_IDS are not affected.

Workaround
----------
Disable JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS in the
juce_audio_plugin_client module config page in the Projucer. For new plug-ins,
be sure to use the default value for this property.

Rationale
--------
JUCE needs to convert between its own JUCE parameter id format (strings) to the
native parameter id formats of the various plug-in backends. For VST3 and
AudioUnits, JUCE uses a hash function to generate a numeric id. However, some
VST3/AudioUnit hosts (specifically Studio One) have a bug that ignore any
parameters that have a negative parameter id. Therefore, the hash function for
VST3/AudioUnits needed to be changed to only return positive-valued hashes.



Version 4.3.0
=============

Change
------
A revised multi-bus API was released which supersedes the previously flawed
multi-bus API - JUCE versions 4.0.0 - 4.2.4 (inclusive).

Possible Issues
---------------
If you have developed a plug-in with JUCE versions 4.0.0 - 4.2.4 (inclusive),
then you will need to update your plug-in to the new multi-bus API. Pre JUCE
4.0.0 plug-ins are not affected apart from other breaking changes listed in
this document.

Woraround
---------
None.

Rationale
--------
A flawed multi-bus API was introduced with JUCE versions 4.0.0 up until version
4.2.4 (inclusive) which was not API compatible with pre JUCE 4 plug-ins. JUCE
4.3.0 releases a revised multi-bus API which restores pre JUCE 4 API
compatibility. However, the new multi-bus API is not compatible with the flawed
multi-bus API (JUCE version 4.0.0 - 4.2.4).


Change
------
JUCE now generates the AAX plug-in bus layout configuration id independent from
the position as it appears in the Projucer’s legacy "Channel layout
configuration" field.

Possible Issues
---------------
ProTools projects generated with a < 4.3.0 JUCE versions of your plug-in, may
load the incorrect bus configuration when upgrading your plug-in to >= 4.3.0
versions of JUCE.

Workaround
----------
Implement AudioProcessor’s getAAXPluginIDForMainBusConfig callback to manually
override which AAX plug-in id is associated to a specific bus layout of your
plug-in. This workaround is only necessary if you have released your plug-in
built with a version previous to JUCE 4.3.0.

Rationale
--------
The new multi-bus API offers more features, flexibility and accuracy in
specifying bus layouts which cannot be expressed by the Projucer’s legacy
"Channel layout configuration" field. The native plug-in format backends use
the new multi-bus callback APIs to negotiate channel layouts with the host -
including the AAX plug-in ids assigned to specific bus layouts. With the
callback API, there is no notion of an order in which the channel
configurations appear - as was the case with the legacy "Channel layout
configuration" field - and therefore cannot be used to generate the AAX plug-in
id. To remain backward compatible to pre JUCE 4.0.0 plug-ins, JUCE does
transparently convert the legacy "Channel layout configuration" field to the
new callback based multi-bus API, but this does not take the order into account
in which the channel configurations appear in the legacy "Channel layout
configuration" field.



Version 4.2.1
=============

Change
------
JUCE now uses the paramID property used in AudioProcessorParameterWithID to
uniquely identify parameters to the host.

Possible Issues
---------------
DAW projects with automation data written by an audio plug-in built with pre
JUCE 4.2.1 will load incorrectly when opened by an audio plug-in built with
JUCE 4.2.1 and later.

Workaround
----------
Enable JUCE_FORCE_USE_LEGACY_IDS in the juce_audio_plugin_client module config
page in the Projucer. For new plug-ins, be sure to disable this property.

Rationale
--------
Each parameter of the AudioProcessor has an id associated so that the plug-in’s
host can uniquely identify parameters. The id has a different data-type for
different plug-in types (for example VST uses integers, AAX uses string
identifiers). Before 4.2.1, JUCE generated the parameter id by using the index
of the parameter, i.e. the first parameter had id zero, the second parameter
had id one, etc. This caused problems for certain plug-in types where JUCE
needs to add internal parameters to the plug-in (for example VST3 requires the
bypass control to be a parameter - so JUCE automatically creates this parameter
for you in the VST3 backend). This causes subtle problems if a parameter is
added to an update of an already published plug-in. The new parameter’s id
would be identical to the id of the bypass parameter in old versions of your
plug-in, causing seemingly random plug-in bypass behaviour when user’s upgrade
their plug-in.

Most plug-in backends differentiate between a parameter’s id an index, so this
distinction was adopted starting with JUCE 4.2.1 by deriving the parameter’s
unique id from the paramID property of AudioProcessorParameterWithID class.

JUCE breaking changes
=====================
Version 5.1.2
=============
Change
------
The method used to classify AudioUnit, VST3 and AAX plug-in parameters as
either continuous or discrete has changed, and AudioUnit and AudioUnit v3
parameters are marked as high precision by default.
Possible Issues
---------------
Plug-ins: DAW projects with automation data written by an AudioUnit, AudioUnit
v3 VST3 or AAX plug-in built with JUCE version 5.1.1 or earlier may load
incorrectly when opened by an AudioUnit, AudioUnit v3, VST3 or AAX plug-in
built with JUCE version 5.1.2 and later.
Hosts: The AudioPluginInstance::getParameterNumSteps method now returns correct
values for AU and VST3 plug-ins.
Workaround
----------
Plug-ins: Enable JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE in the
juce_audio_plugin_client module config page in the Projucer.
Hosts: Use AudioPluginInstance::getDefaultNumParameterSteps as the number of
steps for all parameters.
Rationale
---------
The old system for presenting plug-in parameters to a host as either continuous
or discrete is inconsistent between plug-in types and lacks sufficient
flexibility. This change harmonises the behaviour and allows individual
parameters to be marked as continuous or discrete. If AudioUnit and AudioUnit
v3 parameters are not marked as high precision then hosts like Logic Pro only
offer a limited number of parameter values, which again produces different
behaviour for different plug-in types.
Change
------
A new FrameRateType fps23976 has been added to AudioPlayHead,
Possible Issues
---------------
Previously JUCE would report the FrameRateType fps24 for both 24 and 23.976
fps. If your code uses switch statements (or similar) to handle all possible
frame rate types, then this change may cause it to fall through.
Workaround
----------
Add fps23976 to your switch statement and handle it appropriately.
Rationale
---------
JUCE should be able to handle all popular frame rate codes but was missing
support for 23.976.
Change
------
The String (bool) constructor and operator<< (String&, bool) have been
explicitly deleted.
Possible Issues
---------------
Previous code which relied on an implicit bool to int type conversion to
produce a String will not compile.
Workaround
----------
Cast your bool to an integer to generate a string representation of it.
Rationale
---------
Letting things implicitly convert to bool to produce a String opens the door to
all kinds of nasty type conversion edge cases. Furthermore, before this change,
MacOS would automatically convert bools to ints but this wouldn't occur on
different platform. Now the behaviour is consistent across all operating
systems supported by JUCE.
Change
------
The writeAsJSON virtual method of the DynamicObject class requires an
additional parameter, maximumDecimalPlaces, to specify the maximum precision of
floating point numbers.
Possible Issues
---------------
Classes which inherit from DynamicObject and override this method will need to
update their method signature.
Workaround
----------
Your custom DynamicObject class can choose to ignore the additional parameter
if you don't wish to support this behaviour.
Rationale
---------
When serialising the results of calculations to JSON the rounding of floating
point numbers can result in numbers with 17 significant figures where only a
few are required. This change to DynamicObject is required to support
truncating those numbers.
Version 5.1.0
=============
Change
------
The option to set the C++ language standard is now located in the project
settings instead of the build configuration settings.
Possible Issues
---------------
Projects that had a specific verison of the C++ language standard set for
exporter build configurations will instead use the default (C++11) when
re-saving with the new Projucer.
Workaround
----------
Change the "C++ Language Standard" setting in the main project settings to the
required version - the Projucer will add this value to the exported project as
a compiler flag when saving exporters.
Rationale
---------
Having a different C++ language standard option for each build configuration
was unnecessary and was not fully implemented for all exporters. Changing it to
a per-project settings means that the preference will propagate to all
exporters and only needs to be set in one place.
Change
------
PopupMenus now scale according to the AffineTransform and scaling factor of
their target components.
Possible Issues
---------------
Developers who have manually scaled their PopupMenus to fit the scaling factor
of the parent UI will now have the scaling applied two times in a row.
Workaround
----------
1. Do not apply your own manual scaling to make your popups match the UI
scaling
or
2. Override the Look&Feel method
PopupMenu::LookAndFeelMethods::shouldPopupMenuScaleWithTargetComponent and
return false. See
https://github.com/WeAreROLI/JUCE/blob/c288c94c2914af20f36c03ca9c5401fcb555e4e9/modules/juce_gui_basics/menus/juce_PopupMenu.h#725
Rationale
---------
Previously, PopupMenus would not scale if the GUI of the target component (or
any of it’s parents) were scaled. The only way to scale PopupMenus was via the
global scaling factor. This had several drawbacks as the global scaling factor
would scale everything. This was especially problematic in plug-in editors.
Change
------
Removed the setSecurityFlags() method from the Windows implementation of
WebInputStream as it disabled HTTPS security features.
Possible Issues
---------------
Any code previously relying on connections to insecure webpages succeeding will
no longer work.
Workaround
----------
Check network connectivity on Windows and re-write any code that relied on
insecure connections.
Rationale
---------
The previous behaviour resulted in network connections on Windows having all
the HTTPS security features disabled, exposing users to network attacks. HTTPS
connections on Windows are now secure and will fail when connecting to an
insecure web address.
Change
------
Pointer arithmetic on a pointer will have the same result regardless if it is
wrapped in JUCE's Atomic class or not.
Possible Issues
---------------
Any code using pointer arithmetic on Atomic<T*> will now have a different
result leading to undefined behaviour or crashes.
Workaround
----------
Re-write your code in a way that it does not depend on your pointer being
wrapped in JUCE's Atomic or not. See rationale.
Rationale
---------
Before this change, pointer arithmetic with JUCE's Atomic type would yield
confusing results. For example, the following code would assert before this
change:
int* a; Atomic<int*> b;
jassert (++a == ++b);
Pointer a in the above code would be advanced by sizeof(int) whereas the JUCE's
Atomic always advances it's underlying pointer by a single byte. The same is
true for operator+=/operator-= and operator--. The difference in behaviour is
confusing and unintuitive. Furthermore, this aligns JUCE's Atomic type with
std::atomic.
Version 4.3.1
=============
Change
------
JUCE has changed the way native VST3/AudioUnit parameter ids are calculated.
Possible Issues
---------------
DAW projects with automation data written by an AudioUnit or VST3 plug-in built
with pre JUCE 4.3.1 versions will load incorrectly when opened by an AudioUnit
or VST3 built with JUCE versions 4.3.1 and later. Plug-ins using
JUCE_FORCE_USE_LEGACY_PARAM_IDS are not affected.
Workaround
----------
Disable JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS in the
juce_audio_plugin_client module config page in the Projucer. For new plug-ins,
be sure to use the default value for this property.
Rationale
--------
JUCE needs to convert between its own JUCE parameter id format (strings) to the
native parameter id formats of the various plug-in backends. For VST3 and
AudioUnits, JUCE uses a hash function to generate a numeric id. However, some
VST3/AudioUnit hosts (specifically Studio One) have a bug that ignore any
parameters that have a negative parameter id. Therefore, the hash function for
VST3/AudioUnits needed to be changed to only return positive-valued hashes.
Version 4.3.0
=============
Change
------
A revised multi-bus API was released which supersedes the previously flawed
multi-bus API - JUCE versions 4.0.0 - 4.2.4 (inclusive).
Possible Issues
---------------
If you have developed a plug-in with JUCE versions 4.0.0 - 4.2.4 (inclusive),
then you will need to update your plug-in to the new multi-bus API. Pre JUCE
4.0.0 plug-ins are not affected apart from other breaking changes listed in
this document.
Woraround
---------
None.
Rationale
--------
A flawed multi-bus API was introduced with JUCE versions 4.0.0 up until version
4.2.4 (inclusive) which was not API compatible with pre JUCE 4 plug-ins. JUCE
4.3.0 releases a revised multi-bus API which restores pre JUCE 4 API
compatibility. However, the new multi-bus API is not compatible with the flawed
multi-bus API (JUCE version 4.0.0 - 4.2.4).
Change
------
JUCE now generates the AAX plug-in bus layout configuration id independent from
the position as it appears in the Projucer’s legacy "Channel layout
configuration" field.
Possible Issues
---------------
ProTools projects generated with a < 4.3.0 JUCE versions of your plug-in, may
load the incorrect bus configuration when upgrading your plug-in to >= 4.3.0
versions of JUCE.
Workaround
----------
Implement AudioProcessor’s getAAXPluginIDForMainBusConfig callback to manually
override which AAX plug-in id is associated to a specific bus layout of your
plug-in. This workaround is only necessary if you have released your plug-in
built with a version previous to JUCE 4.3.0.
Rationale
--------
The new multi-bus API offers more features, flexibility and accuracy in
specifying bus layouts which cannot be expressed by the Projucer’s legacy
"Channel layout configuration" field. The native plug-in format backends use
the new multi-bus callback APIs to negotiate channel layouts with the host -
including the AAX plug-in ids assigned to specific bus layouts. With the
callback API, there is no notion of an order in which the channel
configurations appear - as was the case with the legacy "Channel layout
configuration" field - and therefore cannot be used to generate the AAX plug-in
id. To remain backward compatible to pre JUCE 4.0.0 plug-ins, JUCE does
transparently convert the legacy "Channel layout configuration" field to the
new callback based multi-bus API, but this does not take the order into account
in which the channel configurations appear in the legacy "Channel layout
configuration" field.
Version 4.2.1
=============
Change
------
JUCE now uses the paramID property used in AudioProcessorParameterWithID to
uniquely identify parameters to the host.
Possible Issues
---------------
DAW projects with automation data written by an audio plug-in built with pre
JUCE 4.2.1 will load incorrectly when opened by an audio plug-in built with
JUCE 4.2.1 and later.
Workaround
----------
Enable JUCE_FORCE_USE_LEGACY_PARAM_IDS in the juce_audio_plugin_client module config
page in the Projucer. For new plug-ins, be sure to disable this property.
Rationale
--------
Each parameter of the AudioProcessor has an id associated so that the plug-in’s
host can uniquely identify parameters. The id has a different data-type for
different plug-in types (for example VST uses integers, AAX uses string
identifiers). Before 4.2.1, JUCE generated the parameter id by using the index
of the parameter, i.e. the first parameter had id zero, the second parameter
had id one, etc. This caused problems for certain plug-in types where JUCE
needs to add internal parameters to the plug-in (for example VST3 requires the
bypass control to be a parameter - so JUCE automatically creates this parameter
for you in the VST3 backend). This causes subtle problems if a parameter is
added to an update of an already published plug-in. The new parameter’s id
would be identical to the id of the bypass parameter in old versions of your
plug-in, causing seemingly random plug-in bypass behaviour when user’s upgrade
their plug-in.
Most plug-in backends differentiate between a parameter’s id an index, so this
distinction was adopted starting with JUCE 4.2.1 by deriving the parameter’s
unique id from the paramID property of AudioProcessorParameterWithID class.

+ 64
- 50
ChangeList.txt View File

@@ -1,56 +1,70 @@
== Major JUCE features and updates ==
== Major JUCE features and updates ==
This file just lists the more notable headline features. For more detailed info
about minor changes and bugfixes, please see the git log!

Version 5.1.1
- Fixed Windows live build engine on Visual Studio 2017
- Fixed a compiler error in juce_MathFunctions.h in Visual Studio 2013
- Fixed a potential crash when using the ProcessorDuplicator
- Fixed a compiler-error in Filter::IIR
- Fixed an issue where the WavFileFormatWriter could not create files with discrete channels
- Fixed an issue where a window which is beneath a hidden window would not receive any clicks on Linux
- Altered the format of BREAKING-CHANGES.txt to display better on GitHub
- Projucer: Fixed an issue in exporter tilde expansion
- Fixed compiler errors when building the DSP module with a static version of FFTW
- Fixed an audio glitch when bypassing the convolution engine
- Fixed an issue where a JUCE VST2 would not correctly report that it supports resizing of it’s plugin editor
- Various documentation tweaks and fixes

Version 5.1.0
- Release of the JUCE DSP module
- Multichannel audio readers and writers
- Plugin editor Hi-DPI scaling support
- Major improvements to Projucer module search paths
- Added Projucer support for iOS app groups
- Added support for AVFoundation and deprecated the use of Quicktime
- Added a new real-time audio thread priority for Android
- Various Projucer UI fixes
- Various documentation fixes
- Various minor improvements and bug fixes

Version 5.0.2
- Improved project save speed in the Projucer
- Added option to save individual exporters in the Projucer
- Added the ability to create custom colour schemes for the Projucer’s code editor
- Minor fixes to JUCE’s SVG parser
- Various bug fixes in the way JUCE handles Hi-DPI monitors
- Improved code browsing in Visual Studio Exports
- Improved the handling of audio device buffer size changes on iOS
- Fixed bug in the Win32 FileChooser dialog when selecting a nonexistent root drive
- Fixed a Projucer crash when saving projects with no targets
- Fixed a bug where Projucer generated Makefiles would not trigger a recompilation when header files had changed
- The standalone plugin target is now compatible with effect plug-ins
- Fixed an issue where it was not possible to use the live build engine on plugin projects
- Improved the way the Projucer’s live-build engine searches for platform headers on Windows
- Fixed an issue where the Projucer would complain about not having internet even if the user had a license
- Fixed a use-after-free in the AUv3 wrapper
- Fixed an issue where the channel layout would not be reported correctly in the AUv3 wrapper
- Fixed a potential memory overrun issue when hosting VST2 plugins with more than eight channels
- Fixed a problem with the Mac main menu bar showing menus in the wrong position
- Various Projucer UI fixes
- Various documentation fixes
about minor changes and bugfixes, please see the git log!
Version 5.1.2
- Fixed multiple plugin-resizing bugs
- Added support for AUv3 MIDI and screen size negotiation
- Added support for Xcode 9 and iOS 11
- Added an In-App Purchases module
- Added backwards compatible constexpr support
- Standalone plug-in improvements
- Better .jucer file change monitoring in the Projucer
- Increased the speed of AU parameter lookup
- Improved the Android thread management when dealing with web requests
- Better denormal support
- Plug-in parameters can be explicitly marked as continuous or discrete
- Multiple documentation updates
Version 5.1.1
- Fixed Windows live build engine on Visual Studio 2017
- Fixed a compiler error in juce_MathFunctions.h in Visual Studio 2013
- Fixed a potential crash when using the ProcessorDuplicator
- Fixed a compiler-error in Filter::IIR
- Fixed an issue where the WavFileFormatWriter could not create files with discrete channels
- Fixed an issue where a window which is beneath a hidden window would not receive any clicks on Linux
- Altered the format of BREAKING-CHANGES.txt to display better on GitHub
- Projucer: Fixed an issue in exporter tilde expansion
- Fixed compiler errors when building the DSP module with a static version of FFTW
- Fixed an audio glitch when bypassing the convolution engine
- Fixed an issue where a JUCE VST2 would not correctly report that it supports resizing of it’s plugin editor
- Various documentation tweaks and fixes
Version 5.1.0
- Release of the JUCE DSP module
- Multichannel audio readers and writers
- Plugin editor Hi-DPI scaling support
- Major improvements to Projucer module search paths
- Added Projucer support for iOS app groups
- Added support for AVFoundation and deprecated the use of Quicktime
- Added a new real-time audio thread priority for Android
- Various Projucer UI fixes
- Various documentation fixes
- Various minor improvements and bug fixes
Version 5.0.2
- Improved project save speed in the Projucer
- Added option to save individual exporters in the Projucer
- Added the ability to create custom colour schemes for the Projucer’s code editor
- Minor fixes to JUCE’s SVG parser
- Various bug fixes in the way JUCE handles Hi-DPI monitors
- Improved code browsing in Visual Studio Exports
- Improved the handling of audio device buffer size changes on iOS
- Fixed bug in the Win32 FileChooser dialog when selecting a nonexistent root drive
- Fixed a Projucer crash when saving projects with no targets
- Fixed a bug where Projucer generated Makefiles would not trigger a recompilation when header files had changed
- The standalone plugin target is now compatible with effect plug-ins
- Fixed an issue where it was not possible to use the live build engine on plugin projects
- Improved the way the Projucer’s live-build engine searches for platform headers on Windows
- Fixed an issue where the Projucer would complain about not having internet even if the user had a license
- Fixed a use-after-free in the AUv3 wrapper
- Fixed an issue where the channel layout would not be reported correctly in the AUv3 wrapper
- Fixed a potential memory overrun issue when hosting VST2 plugins with more than eight channels
- Fixed a problem with the Mac main menu bar showing menus in the wrong position
- Various Projucer UI fixes
- Various documentation fixes
- Various minor improvements and bug fixes
Version 5.0.1


+ 1
- 1
examples/AUv3Synth/AUv3Synth.jucer View File

@@ -8,7 +8,7 @@
pluginCode="AUv3" pluginChannelConfigs="" pluginIsSynth="1" pluginWantsMidiIn="1"
pluginProducesMidiOut="0" pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="AUv3SynthAU" pluginRTASCategory="" aaxIdentifier="com.roli.development.AUv3Synth"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.1"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.2"
buildStandalone="1" enableIAA="0" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="h0gx6L" name="AUv3Synth">


+ 4
- 0
examples/AUv3Synth/JuceLibraryCode/AppConfig.h View File

@@ -101,6 +101,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 6
- 9
examples/AUv3Synth/Source/AUv3SynthProcessor.cpp View File

@@ -96,19 +96,16 @@ public:
const String getName() const override { return "AUv3 Synth"; }
int getNumPrograms() override { return 4; }
int getCurrentProgram() override { return currentProgram; }
void setCurrentProgram (int index) override { currentProgram = index; }
void setCurrentProgram (int index) override { currentProgram = index; }
const String getProgramName (int index) override
{
switch (index)
{
case 0:
return "Piano";
case 1:
return "Singing";
case 2:
return "Pinched Balloon";
case 3:
return "Gazeebo";
case 0: return "Piano";
case 1: return "Singing";
case 2: return "Pinched Balloon";
case 3: return "Gazeebo";
}
return "<Unknown>";


+ 1
- 1
examples/AnimationAppExample/AnimationAppExample.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="LrATE6" name="AnimationAppExample" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.AnimationAppExample" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="F3keCY" name="AnimationAppExample">
<GROUP id="{5E4132EA-C4A0-CBDE-BEDA-FD6772DA79D5}" name="Source">


+ 1
- 1
examples/AudioAppExample/AudioAppExample.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="PAnJXP" name="AudioAppExample" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.AudioAppExample" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="GaJIge" name="AudioAppExample">
<GROUP id="{168FC5D4-FA65-8320-F83E-C14C416638E1}" name="Source">


+ 1
- 1
examples/BLOCKS/BlocksDrawing/BlocksDrawing.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="aa4reI" name="BlocksDrawing" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.yourcompany.BlocksDrawing" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" cppLanguageStandard="11">
<MAINGROUP id="yXiPIx" name="BlocksDrawing">
<GROUP id="{092A4D5B-31E2-5D03-9B41-81C10EC447E8}" name="Source">


+ 1
- 1
examples/BLOCKS/BlocksMonitor/BlocksMonitor.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="X7eXs7" name="BlocksMonitor" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.yourcompany.BlocksInfo" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" cppLanguageStandard="11">
<MAINGROUP id="msZ9DB" name="BlocksMonitor">
<GROUP id="{2C318C74-6596-8102-3CA6-602595447F25}" name="Source">


+ 1
- 1
examples/BLOCKS/BlocksSynth/BlocksSynth.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="XsTycT" name="BlocksSynth" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.yourcompany.BlocksSynth" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" cppLanguageStandard="11">
<MAINGROUP id="onTNql" name="BlocksSynth">
<GROUP id="{0CEBC63B-4C52-E77F-CD6E-A2E65F0C9B2B}" name="Source">


+ 1
- 1
examples/BouncingBallWavetableDemo/BouncingBallWavetableDemo.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="fyUrFS" name="BouncingBallWavetableDemo" projectType="guiapp"
version="1.0.0" bundleIdentifier="com.juce.BouncingBallWavetableDemo"
includeBinaryInAppConfig="1" jucerVersion="5.1.1" displaySplashScreen="0"
includeBinaryInAppConfig="1" jucerVersion="5.1.2" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">
<MAINGROUP id="MgjqDB" name="BouncingBallWavetableDemo">


+ 1
- 1
examples/ComponentTutorialExample/ComponentTutorialExample.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="oNvA5C" name="ComponentTutorialExample" projectType="guiapp"
version="1.0.0" bundleIdentifier="com.roli.ComponentTutorialExample"
includeBinaryInAppConfig="1" jucerVersion="5.1.1" displaySplashScreen="0"
includeBinaryInAppConfig="1" jucerVersion="5.1.2" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">
<MAINGROUP id="WydTVz" name="ComponentTutorialExample">


+ 2
- 2
examples/DSP module plugin demo/DSP module plugin demo.jucer View File

@@ -11,7 +11,7 @@
pluginProducesMidiOut="0" pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="DSPmoduleplugindemoAU" pluginRTASCategory=""
aaxIdentifier="com.yourcompany.DSPmoduleplugindemo" pluginAAXCategory="AAX_ePlugInCategory_Dynamics"
jucerVersion="5.1.1" companyName="ROLI Ltd." companyWebsite="www.juce.com"
jucerVersion="5.1.2" companyName="ROLI Ltd." companyWebsite="www.juce.com"
companyEmail="info@juce.com" cppLanguageStandard="14">
<MAINGROUP id="EukfoT" name="DSPModulePluginDemo">
<GROUP id="{03DB4847-1567-1194-A0D2-ECC6C6C5042C}" name="Resources">
@@ -125,5 +125,5 @@
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_opengl" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
</MODULES>
<JUCEOPTIONS JUCE_QUICKTIME="disabled"/>
<JUCEOPTIONS JUCE_QUICKTIME="disabled" JUCE_DSP_ENABLE_SNAP_TO_ZERO="disabled"/>
</JUCERPROJECT>

+ 8
- 0
examples/DSP module plugin demo/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif
@@ -187,6 +191,10 @@
//#define JUCE_DSP_USE_STATIC_FFTW 1
#endif
#ifndef JUCE_DSP_ENABLE_SNAP_TO_ZERO
#define JUCE_DSP_ENABLE_SNAP_TO_ZERO 0
#endif
//==============================================================================
// juce_events flags:


+ 22
- 2
examples/DSP module plugin demo/Source/PluginEditor.cpp View File

@@ -123,6 +123,10 @@ DspModulePluginDemoAudioProcessorEditor::DspModulePluginDemoAudioProcessorEditor
cabinetSimButton.addListener (this);
cabinetSimButton.setButtonText (processor.cabinetSimParam->name);
addAndMakeVisible (oversamplingButton);
oversamplingButton.addListener (this);
oversamplingButton.setButtonText (processor.oversamplingParam->name);
//==============================================================================
setSize (600, 400);
}
@@ -172,9 +176,13 @@ void DspModulePluginDemoAudioProcessorEditor::resized()
//==============================================================================
auto buttonSlice = bounds.removeFromTop (30);
cabinetSimButton.setSize (200, bounds.getHeight());
cabinetSimButton.setSize (200, buttonSlice.getHeight());
cabinetSimButton.setCentrePosition (buttonSlice.getCentre());
bounds.removeFromTop (15);
bounds.removeFromTop(5);
buttonSlice = bounds.removeFromTop (30);
oversamplingButton.setSize(200, buttonSlice.getHeight());
oversamplingButton.setCentrePosition(buttonSlice.getCentre());
}
//==============================================================================
void DspModulePluginDemoAudioProcessorEditor::comboBoxChanged (ComboBox* box)
@@ -198,3 +206,15 @@ void DspModulePluginDemoAudioProcessorEditor::comboBoxChanged (ComboBox* box)
processor.cabinetTypeParam->operator= (index);
}
}
void DspModulePluginDemoAudioProcessorEditor::buttonClicked (Button* button)
{
if (button == &cabinetSimButton)
{
processor.cabinetSimParam->operator= (cabinetSimButton.getToggleState());
}
else if (button == &oversamplingButton)
{
processor.oversamplingParam->operator= (oversamplingButton.getToggleState());
}
}

+ 2
- 2
examples/DSP module plugin demo/Source/PluginEditor.h View File

@@ -86,7 +86,7 @@ public:
private:
//==============================================================================
void comboBoxChanged (ComboBox*) override;
void buttonClicked (Button*) override { processor.cabinetSimParam->operator= (cabinetSimButton.getToggleState()); }
void buttonClicked (Button*) override;
//==============================================================================
DspModulePluginDemoAudioProcessor& processor;
@@ -94,7 +94,7 @@ private:
ScopedPointer<ParameterSlider> inputVolumeSlider, outputVolumeSlider,
lowPassFilterFreqSlider, highPassFilterFreqSlider;
ComboBox stereoBox, slopeBox, waveshaperBox, cabinetTypeBox;
ToggleButton cabinetSimButton;
ToggleButton cabinetSimButton, oversamplingButton;
Label inputVolumeLabel, outputVolumeLabel, lowPassFilterFreqLabel,
highPassFilterFreqLabel, stereoLabel, slopeLabel, waveshaperLabel,


+ 40
- 10
examples/DSP module plugin demo/Source/PluginProcessor.cpp View File

@@ -38,6 +38,9 @@ DspModulePluginDemoAudioProcessor::DspModulePluginDemoAudioProcessor()
waveShapers { {std::tanh}, {dsp::FastMathApproximations::tanh} },
clipping { clip }
{
// Oversampling 2 times with IIR filtering
oversampling = new dsp::Oversampling<float> (2, 1, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR, false);
addParameter (inputVolumeParam = new AudioParameterFloat ("INPUT", "Input Volume", { 0.f, 60.f, 0.f, 1.0f }, 0.f, "dB"));
addParameter (highPassFilterFreqParam = new AudioParameterFloat ("HPFREQ", "Pre Highpass Freq.", { 20.f, 20000.f, 0.f, 0.5f }, 20.f, "Hz"));
addParameter (lowPassFilterFreqParam = new AudioParameterFloat ("LPFREQ", "Post Lowpass Freq.", { 20.f, 20000.f, 0.f, 0.5f }, 20000.f, "Hz"));
@@ -50,12 +53,11 @@ DspModulePluginDemoAudioProcessor::DspModulePluginDemoAudioProcessor()
"Cassette recorder cabinet" }, 0));
addParameter (cabinetSimParam = new AudioParameterBool ("CABSIM", "Cabinet Sim", false));
addParameter (oversamplingParam = new AudioParameterBool ("OVERS", "Oversampling", false));
addParameter (outputVolumeParam = new AudioParameterFloat ("OUTPUT", "Output Volume", { -40.f, 40.f, 0.f, 1.0f }, 0.f, "dB"));
cabinetType.set (0);
}
DspModulePluginDemoAudioProcessor::~DspModulePluginDemoAudioProcessor()
@@ -82,8 +84,6 @@ void DspModulePluginDemoAudioProcessor::prepareToPlay (double sampleRate, int sa
auto channels = static_cast<uint32> (jmin (getMainBusNumInputChannels(), getMainBusNumOutputChannels()));
dsp::ProcessSpec spec { sampleRate, static_cast<uint32> (samplesPerBlock), channels };
updateParameters();
lowPassFilter.prepare (spec);
highPassFilter.prepare (spec);
@@ -92,6 +92,11 @@ void DspModulePluginDemoAudioProcessor::prepareToPlay (double sampleRate, int sa
convolution.prepare (spec);
cabinetType.set (-1);
oversampling->initProcessing (static_cast<size_t> (samplesPerBlock));
updateParameters();
reset();
}
void DspModulePluginDemoAudioProcessor::reset()
@@ -99,6 +104,7 @@ void DspModulePluginDemoAudioProcessor::reset()
lowPassFilter.reset();
highPassFilter.reset();
convolution.reset();
oversampling->reset();
}
void DspModulePluginDemoAudioProcessor::releaseResources()
@@ -108,6 +114,8 @@ void DspModulePluginDemoAudioProcessor::releaseResources()
void DspModulePluginDemoAudioProcessor::process (dsp::ProcessContextReplacing<float> context) noexcept
{
ScopedNoDenormals noDenormals;
// Input volume applied with a LinearSmoothedValue
inputVolume.process (context);
@@ -115,20 +123,34 @@ void DspModulePluginDemoAudioProcessor::process (dsp::ProcessContextReplacing<fl
// Note : try frequencies around 700 Hz
highPassFilter.process (context);
// Upsampling
dsp::AudioBlock<float> oversampledBlock;
setLatencySamples (audioCurrentlyOversampled ? roundFloatToInt (oversampling->getLatencyInSamples()) : 0);
if (audioCurrentlyOversampled)
oversampledBlock = oversampling->processSamplesUp (context.getInputBlock());
dsp::ProcessContextReplacing<float> waveshaperContext = audioCurrentlyOversampled ? dsp::ProcessContextReplacing<float> (oversampledBlock) : context;
// Waveshaper processing, for distortion generation, thanks to the input gain
// The fast tanh can be used instead of std::tanh to reduce the CPU load
auto waveshaperIndex = waveshaperParam->getIndex();
if (isPositiveAndBelow (waveshaperIndex, (int) numWaveShapers) )
{
waveShapers[waveshaperIndex].process (context);
waveShapers[waveshaperIndex].process (waveshaperContext);
if (waveshaperIndex == 1)
clipping.process(context);
clipping.process (waveshaperContext);
context.getOutputBlock() *= 0.7f;
waveshaperContext.getOutputBlock() *= 0.7f;
}
// Downsampling
if (audioCurrentlyOversampled)
oversampling->processSamplesDown (context.getOutputBlock());
// Post-lowpass filtering
lowPassFilter.process (context);
@@ -209,13 +231,20 @@ bool DspModulePluginDemoAudioProcessor::producesMidi() const
//==============================================================================
void DspModulePluginDemoAudioProcessor::updateParameters()
{
auto newOversampling = oversamplingParam->get();
if (newOversampling != audioCurrentlyOversampled)
{
audioCurrentlyOversampled = newOversampling;
oversampling->reset();
}
//==============================================================================
auto inputdB = Decibels::decibelsToGain (inputVolumeParam->get());
auto outputdB = Decibels::decibelsToGain (outputVolumeParam->get());
if (inputVolume.getGainLinear() != inputdB) inputVolume.setGainLinear (inputdB);
if (outputVolume.getGainLinear() != outputdB) outputVolume.setGainLinear (outputdB);
dsp::IIR::Coefficients<float>::Ptr newHighPassCoeffs, newLowPassCoeffs;
auto newSlopeType = slopeParam->getIndex();
if (newSlopeType == 0)
@@ -240,12 +269,13 @@ void DspModulePluginDemoAudioProcessor::updateParameters()
auto maxSize = static_cast<size_t> (roundDoubleToInt (8192 * getSampleRate() / 44100));
if (type == 0)
convolution.loadImpulseResponse (BinaryData::Impulse1_wav, BinaryData::Impulse1_wavSize, false, maxSize);
convolution.loadImpulseResponse (BinaryData::Impulse1_wav, BinaryData::Impulse1_wavSize, false, true, maxSize);
else
convolution.loadImpulseResponse (BinaryData::Impulse2_wav, BinaryData::Impulse2_wavSize, false, maxSize);
convolution.loadImpulseResponse (BinaryData::Impulse2_wav, BinaryData::Impulse2_wavSize, false, true, maxSize);
}
cabinetIsBypassed = ! cabinetSimParam->get();
}
//==============================================================================


+ 4
- 0
examples/DSP module plugin demo/Source/PluginProcessor.h View File

@@ -88,6 +88,7 @@ public:
AudioParameterChoice* cabinetTypeParam;
AudioParameterBool* cabinetSimParam;
AudioParameterBool* oversamplingParam;
private:
//==============================================================================
@@ -103,6 +104,9 @@ private:
dsp::Gain<float> inputVolume, outputVolume;
ScopedPointer<dsp::Oversampling<float>> oversampling;
bool audioCurrentlyOversampled = false;
Atomic<int> cabinetType;
bool cabinetIsBypassed = false;


+ 1
- 1
examples/DSPDemo/DSPDemo.jucer View File

@@ -3,7 +3,7 @@
<JUCERPROJECT id="yVderJ" name="DSPDemo" displaySplashScreen="1" reportAppUsage="1"
splashScreenColour="Dark" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.DSPDemo" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" cppLanguageStandard="14" companyName="ROLI Ltd."
jucerVersion="5.1.2" cppLanguageStandard="14" companyName="ROLI Ltd."
companyWebsite="www.juce.com" companyEmail="info@juce.com">
<MAINGROUP id="vJBLPL" name="DSPDemo">
<GROUP id="{EF78091C-1BFD-651B-9BAA-893A127B90F5}" name="Source">


+ 4
- 0
examples/DSPDemo/JuceLibraryCode/AppConfig.h View File

@@ -174,6 +174,10 @@
//#define JUCE_DSP_USE_STATIC_FFTW 1
#endif
#ifndef JUCE_DSP_ENABLE_SNAP_TO_ZERO
//#define JUCE_DSP_ENABLE_SNAP_TO_ZERO 1
#endif
//==============================================================================
// juce_events flags:


+ 3
- 3
examples/DSPDemo/JuceLibraryCode/BinaryData.cpp View File

@@ -1565,11 +1565,11 @@ static const unsigned char temp_binary_data_3[] =
" if (cabinetTypeParameter->getCurrentSelectedID() == 2)\r\n"
" convolution.loadImpulseResponse (BinaryData::guitar_amp_wav,\r\n"
" BinaryData::guitar_amp_wavSize,\r\n"
" false, maxSize);\r\n"
" false, true, maxSize);\r\n"
" else\r\n"
" convolution.loadImpulseResponse (BinaryData::cassette_recorder_wav,\r\n"
" BinaryData::cassette_recorder_wavSize,\r\n"
" false, maxSize);\r\n"
" false, true, maxSize);\r\n"
" }\r\n"
" }\r\n"
" }\r\n"
@@ -2325,7 +2325,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw
case 0x409ff6ec: numBytes = 37902; return cassette_recorder_wav;
case 0x69523d16: numBytes = 628; return EditorColourScheme_xml;
case 0x700ccf3c: numBytes = 90246; return guitar_amp_wav;
case 0x5922ccdf: numBytes = 2999; return ConvolutionDemo_cpp;
case 0x5922ccdf: numBytes = 3011; return ConvolutionDemo_cpp;
case 0x14aa0aae: numBytes = 2674; return FIRFilterDemo_cpp;
case 0xab621a06: numBytes = 1809; return GainDemo_cpp;
case 0x06a7a4b1: numBytes = 2819; return IIRFilterDemo_cpp;


+ 1
- 1
examples/DSPDemo/JuceLibraryCode/BinaryData.h View File

@@ -18,7 +18,7 @@ namespace BinaryData
const int guitar_amp_wavSize = 90246;
extern const char* ConvolutionDemo_cpp;
const int ConvolutionDemo_cppSize = 2999;
const int ConvolutionDemo_cppSize = 3011;
extern const char* FIRFilterDemo_cpp;
const int FIRFilterDemo_cppSize = 2674;


+ 2
- 2
examples/DSPDemo/Source/Demos/ConvolutionDemo.cpp View File

@@ -65,11 +65,11 @@ struct ConvolutionDemo
if (cabinetTypeParameter->getCurrentSelectedID() == 2)
convolution.loadImpulseResponse (BinaryData::guitar_amp_wav,
BinaryData::guitar_amp_wavSize,
false, maxSize);
false, true, maxSize);
else
convolution.loadImpulseResponse (BinaryData::cassette_recorder_wav,
BinaryData::cassette_recorder_wavSize,
false, maxSize);
false, true, maxSize);
}
}
}


+ 209
- 103
examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java View File

@@ -519,11 +519,18 @@ public class JuceDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 0);
}
});
@@ -538,11 +545,18 @@ public class JuceDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 1);
}
})
@@ -550,7 +564,7 @@ public class JuceDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 0);
}
});
@@ -564,11 +578,18 @@ public class JuceDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 1);
}
})
@@ -576,7 +597,7 @@ public class JuceDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 2);
}
})
@@ -584,7 +605,7 @@ public class JuceDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemo.this.alertDismissed (callback, 0);
}
});
@@ -982,13 +1003,75 @@ public class JuceDemo extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1011,19 +1094,12 @@ public class JuceDemo extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1031,6 +1107,89 @@ public class JuceDemo extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1068,9 +1227,16 @@ public class JuceDemo extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -1173,13 +1339,20 @@ public class JuceDemo extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -1201,89 +1374,15 @@ public class JuceDemo extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -1309,7 +1408,14 @@ public class JuceDemo extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -1404,7 +1510,7 @@ public class JuceDemo extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 1
- 1
examples/Demo/JuceDemo.jucer View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="sBBIzr" name="JuceDemo" projectType="guiapp" version="3.0.0"
bundleIdentifier="com.roli.JuceDemo" jucerVersion="5.1.1" defines="JUCE_UNIT_TESTS=1"
bundleIdentifier="com.roli.JuceDemo" jucerVersion="5.1.2" defines="JUCE_UNIT_TESTS=1"
includeBinaryInAppConfig="1" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<EXPORTFORMATS>


+ 4
- 0
examples/Demo/Source/Demos/GridDemo.cpp View File

@@ -26,6 +26,8 @@
#include "../JuceDemoHeader.h"
// these classes are C++11-only
#if JUCE_HAS_CONSTEXPR
struct GridDemo : public Component
{
@@ -116,3 +118,5 @@ struct GridDemo : public Component
// This static object will register this demo type in a global list of demos..
static JuceDemoType<GridDemo> demo ("10 Components: GridDemo");
#endif // JUCE_HAS_CONSTEXPR

+ 1
- 1
examples/Demo/Source/Demos/VideoDemo.cpp View File

@@ -26,7 +26,7 @@
#include "../JuceDemoHeader.h"
#if JUCE_MAC || JUCE_DIRECTSHOW
#if JUCE_MAC || (JUCE_WINDOWS && ! JUCE_MINGW)
//==============================================================================
// so that we can easily have two video windows each with a file browser, wrap this up as a class..


+ 47
- 25
examples/Demo/Source/Demos/WidgetsDemo.cpp View File

@@ -105,10 +105,13 @@ struct SlidersPage : public Component
: hintLabel ("hint", "Try right-clicking on a slider for an options menu. \n\n"
"Also, holding down CTRL while dragging will turn on a slider's velocity-sensitive mode")
{
Rectangle<int> layoutArea { 20, 20, 580, 430 };
auto sliderArea = layoutArea.removeFromTop (320);
Slider* s = createSlider (false);
s->setSliderStyle (Slider::LinearVertical);
s->setTextBoxStyle (Slider::TextBoxBelow, false, 100, 20);
s->setBounds (10, 25, 70, 200);
s->setBounds (sliderArea.removeFromLeft (70));
s->setDoubleClickReturnValue (true, 50.0); // double-clicking this slider will set it to 50.0
s->setTextValueSuffix (" units");
@@ -117,68 +120,85 @@ struct SlidersPage : public Component
s->setVelocityBasedMode (true);
s->setSkewFactor (0.5);
s->setTextBoxStyle (Slider::TextBoxAbove, true, 100, 20);
s->setBounds (85, 25, 70, 200);
s->setBounds (sliderArea.removeFromLeft (70));
s->setTextValueSuffix (" rels");
sliderArea.removeFromLeft (20);
auto horizonalSliderArea = sliderArea.removeFromLeft (180);
s = createSlider (true);
s->setSliderStyle (Slider::LinearHorizontal);
s->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
s->setBounds (180, 35, 150, 20);
s->setBounds (horizonalSliderArea.removeFromTop (20));
s = createSlider (false);
s->setSliderStyle (Slider::LinearHorizontal);
s->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
s->setBounds (180, 65, 150, 20);
horizonalSliderArea.removeFromTop (20);
s->setBounds (horizonalSliderArea.removeFromTop (20));
s->setPopupDisplayEnabled (true, false, this);
s->setTextValueSuffix (" nuns required to change a lightbulb");
s = createSlider (false);
s->setSliderStyle (Slider::LinearHorizontal);
s->setTextBoxStyle (Slider::TextEntryBoxPosition::TextBoxAbove, false, 70, 20);
horizonalSliderArea.removeFromTop (20);
s->setBounds (horizonalSliderArea.removeFromTop (50));
s->setPopupDisplayEnabled (true, false, this);
s = createSlider (false);
s->setSliderStyle (Slider::IncDecButtons);
s->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
s->setBounds (180, 105, 100, 20);
horizonalSliderArea.removeFromTop (20);
s->setBounds (horizonalSliderArea.removeFromTop (20));
s->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
s = createSlider (false);
s->setSliderStyle (Slider::Rotary);
s->setRotaryParameters (float_Pi * 1.2f, float_Pi * 2.8f, false);
s->setTextBoxStyle (Slider::TextBoxRight, false, 70, 20);
s->setBounds (190, 145, 120, 40);
horizonalSliderArea.removeFromTop (15);
s->setBounds (horizonalSliderArea.removeFromTop (70));
s->setTextValueSuffix (" mm");
s = createSlider (false);
s->setSliderStyle (Slider::LinearBar);
s->setBounds (180, 195, 100, 30);
horizonalSliderArea.removeFromTop (10);
s->setBounds (horizonalSliderArea.removeFromTop (30));
s->setTextValueSuffix (" gallons");
sliderArea.removeFromLeft (20);
auto twoValueSliderArea = sliderArea.removeFromLeft (180);
s = createSlider (false);
s->setSliderStyle (Slider::TwoValueHorizontal);
s->setBounds (360, 20, 160, 40);
s->setBounds (twoValueSliderArea.removeFromTop (40));
s = createSlider (false);
s->setSliderStyle (Slider::TwoValueVertical);
s->setBounds (360, 110, 40, 160);
s->setSliderStyle (Slider::ThreeValueHorizontal);
s->setPopupDisplayEnabled (true, false, this);
twoValueSliderArea.removeFromTop (10);
s->setBounds (twoValueSliderArea.removeFromTop (40));
s = createSlider (false);
s->setSliderStyle (Slider::ThreeValueHorizontal);
s->setBounds (360, 70, 160, 40);
s->setSliderStyle (Slider::TwoValueVertical);
twoValueSliderArea.removeFromLeft (30);
s->setBounds (twoValueSliderArea.removeFromLeft (40));
s = createSlider (false);
s->setSliderStyle (Slider::ThreeValueVertical);
s->setBounds (440, 110, 40, 160);
s->setPopupDisplayEnabled (true, false, this);
twoValueSliderArea.removeFromLeft (30);
s->setBounds (twoValueSliderArea.removeFromLeft (40));
s = createSlider (false);
s->setSliderStyle (Slider::LinearBarVertical);
s->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
s->setBounds (540, 35, 20, 230);
sliderArea.removeFromLeft (20);
s->setBounds (sliderArea.removeFromLeft (20));
s->setPopupDisplayEnabled (true, true, this);
s->setTextValueSuffix (" mickles in a muckle");
for (int i = 7; i <= 10; ++i)
{
sliders.getUnchecked(i)->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
sliders.getUnchecked(i)->setPopupDisplayEnabled (true, false, this);
}
/* Here, we'll create a Value object, and tell a bunch of our sliders to use it as their
value source. By telling them all to share the same Value, they'll stay in sync with
each other.
@@ -188,7 +208,7 @@ struct SlidersPage : public Component
*/
Value sharedValue;
sharedValue = Random::getSystemRandom().nextDouble() * 100;
for (int i = 0; i < 7; ++i)
for (int i = 0; i < 8; ++i)
sliders.getUnchecked(i)->getValueObject().referTo (sharedValue);
// ..and now we'll do the same for all our min/max slider values..
@@ -196,13 +216,15 @@ struct SlidersPage : public Component
sharedValueMin = Random::getSystemRandom().nextDouble() * 40.0;
sharedValueMax = Random::getSystemRandom().nextDouble() * 40.0 + 60.0;
for (int i = 7; i <= 10; ++i)
for (int i = 8; i <= 11; ++i)
{
sliders.getUnchecked(i)->getMaxValueObject().referTo (sharedValueMax);
sliders.getUnchecked(i)->getMinValueObject().referTo (sharedValueMin);
auto* selectedSlider = sliders.getUnchecked(i);
selectedSlider->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
selectedSlider->getMaxValueObject().referTo (sharedValueMax);
selectedSlider->getMinValueObject().referTo (sharedValueMin);
}
hintLabel.setBounds (20, 245, 350, 150);
hintLabel.setBounds (layoutArea);
addAndMakeVisible (hintLabel);
}


+ 1
- 1
examples/HelloWorld/HelloWorld.jucer View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="tTAKTK1s" name="HelloWorld" projectType="guiapp" juceFolder="../../../juce"
jucerVersion="5.1.1" version="1.0.0" bundleIdentifier="com.roli.jucehelloworld"
jucerVersion="5.1.2" version="1.0.0" bundleIdentifier="com.roli.jucehelloworld"
companyName="ROLI Ltd." includeBinaryInAppConfig="1" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" cppLanguageStandard="11">
<EXPORTFORMATS>


+ 1
- 1
examples/InAppPurchase/Builds/Android/app/CMakeLists.txt View File

@@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni")
add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=10" "-DJUCE_ANDROID_ACTIVITY_CLASSNAME=com_roli_juceinapppurchasesample_InAppPurchase" "-DJUCE_ANDROID_ACTIVITY_CLASSPATH=\"com/roli/juceinapppurchasesample/InAppPurchase\"" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=0.0.2" "-DJUCE_APP_VERSION_HEX=0x2")
add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=10" "-DJUCE_ANDROID_ACTIVITY_CLASSNAME=com_roli_juceinapppurchasesample_InAppPurchase" "-DJUCE_ANDROID_ACTIVITY_CLASSPATH=\"com/roli/juceinapppurchasesample/InAppPurchase\"" "-DJUCE_IN_APP_PURCHASES=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=0.0.2" "-DJUCE_APP_VERSION_HEX=0x2")
include_directories( AFTER
"../../../JuceLibraryCode"


+ 209
- 103
examples/InAppPurchase/Builds/Android/app/src/main/java/com/roli/juceinapppurchasesample/InAppPurchase.java View File

@@ -519,11 +519,18 @@ public class InAppPurchase extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
InAppPurchase.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 0);
}
});
@@ -538,11 +545,18 @@ public class InAppPurchase extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
InAppPurchase.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 1);
}
})
@@ -550,7 +564,7 @@ public class InAppPurchase extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 0);
}
});
@@ -564,11 +578,18 @@ public class InAppPurchase extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
InAppPurchase.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 1);
}
})
@@ -576,7 +597,7 @@ public class InAppPurchase extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 2);
}
})
@@ -584,7 +605,7 @@ public class InAppPurchase extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
InAppPurchase.this.alertDismissed (callback, 0);
}
});
@@ -982,13 +1003,75 @@ public class InAppPurchase extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1011,19 +1094,12 @@ public class InAppPurchase extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1031,6 +1107,89 @@ public class InAppPurchase extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1068,9 +1227,16 @@ public class InAppPurchase extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -1173,13 +1339,20 @@ public class InAppPurchase extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -1201,89 +1374,15 @@ public class InAppPurchase extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -1309,7 +1408,14 @@ public class InAppPurchase extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -1404,7 +1510,7 @@ public class InAppPurchase extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 2
- 0
examples/InAppPurchase/Builds/iOS/InAppPurchase.xcodeproj/project.pbxproj View File

@@ -223,6 +223,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"_DEBUG=1",
"DEBUG=1",
"JUCE_IN_APP_PURCHASES=1",
"JUCER_XCODE_IPHONE_5BC26AE3=1",
"JUCE_APP_VERSION=0.0.2",
"JUCE_APP_VERSION_HEX=0x2",
@@ -254,6 +255,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"_NDEBUG=1",
"NDEBUG=1",
"JUCE_IN_APP_PURCHASES=1",
"JUCER_XCODE_IPHONE_5BC26AE3=1",
"JUCE_APP_VERSION=0.0.2",
"JUCE_APP_VERSION_HEX=0x2",


+ 1
- 1
examples/InAppPurchase/InAppPurchase.jucer View File

@@ -3,7 +3,7 @@
<JUCERPROJECT id="bSx0Ct" name="InAppPurchase" displaySplashScreen="0" reportAppUsage="1"
splashScreenColour="Dark" projectType="guiapp" version="0.0.2"
bundleIdentifier="com.roli.juceInAppPurchaseSample" includeBinaryInAppConfig="1"
cppLanguageStandard="11" jucerVersion="5.1.1" companyName="ROLI Ltd."
cppLanguageStandard="11" jucerVersion="5.1.2" companyName="ROLI Ltd."
companyWebsite="www.juce.com" companyEmail="info@juce.com">
<MAINGROUP id="y4sxBT" name="InAppPurchase">
<GROUP id="{D5BB0A26-3258-B6DA-ED7A-A306325E64AE}" name="BinaryData">


+ 1
- 1
examples/MPETest/MPETest.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="IilE7R" name="MPETest" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.MPETest" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="VCQQcn" name="MPETest">
<GROUP id="{D43238F0-992F-BC5A-F1AA-31BBBD3D17B0}" name="Source">


+ 209
- 103
examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java View File

@@ -1448,11 +1448,18 @@ public class MidiTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
MidiTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 0);
}
});
@@ -1467,11 +1474,18 @@ public class MidiTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
MidiTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 1);
}
})
@@ -1479,7 +1493,7 @@ public class MidiTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 0);
}
});
@@ -1493,11 +1507,18 @@ public class MidiTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
MidiTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 1);
}
})
@@ -1505,7 +1526,7 @@ public class MidiTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 2);
}
})
@@ -1513,7 +1534,7 @@ public class MidiTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
MidiTest.this.alertDismissed (callback, 0);
}
});
@@ -1911,13 +1932,75 @@ public class MidiTest extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1940,19 +2023,12 @@ public class MidiTest extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1960,6 +2036,89 @@ public class MidiTest extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1997,9 +2156,16 @@ public class MidiTest extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -2102,13 +2268,20 @@ public class MidiTest extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -2130,89 +2303,15 @@ public class MidiTest extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -2238,7 +2337,14 @@ public class MidiTest extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -2333,7 +2439,7 @@ public class MidiTest extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 1
- 1
examples/MidiTest/MidiTest.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="wHE0ay" name="MidiTest" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.MidiTest" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="s3xxCh" name="MidiTest">
<GROUP id="{7D29F5BC-1B05-AE8F-9202-5CF152AB1103}" name="Source">


+ 209
- 103
examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java View File

@@ -519,11 +519,18 @@ public class JUCENetworkGraphicsDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
});
@@ -538,11 +545,18 @@ public class JUCENetworkGraphicsDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1);
}
})
@@ -550,7 +564,7 @@ public class JUCENetworkGraphicsDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
});
@@ -564,11 +578,18 @@ public class JUCENetworkGraphicsDemo extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1);
}
})
@@ -576,7 +597,7 @@ public class JUCENetworkGraphicsDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 2);
}
})
@@ -584,7 +605,7 @@ public class JUCENetworkGraphicsDemo extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0);
}
});
@@ -982,13 +1003,75 @@ public class JUCENetworkGraphicsDemo extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1011,19 +1094,12 @@ public class JUCENetworkGraphicsDemo extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1031,6 +1107,89 @@ public class JUCENetworkGraphicsDemo extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1068,9 +1227,16 @@ public class JUCENetworkGraphicsDemo extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -1173,13 +1339,20 @@ public class JUCENetworkGraphicsDemo extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -1201,89 +1374,15 @@ public class JUCENetworkGraphicsDemo extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -1309,7 +1408,14 @@ public class JUCENetworkGraphicsDemo extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -1404,7 +1510,7 @@ public class JUCENetworkGraphicsDemo extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 1
- 1
examples/NetworkGraphicsDemo/NetworkGraphicsDemo.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="gWI5Ir" name="JUCE Network Graphics Demo" projectType="guiapp"
version="1.0.0" bundleIdentifier="com.juce.NetworkGraphicsDemo"
includeBinaryInAppConfig="1" jucerVersion="5.1.1" displaySplashScreen="0"
includeBinaryInAppConfig="1" jucerVersion="5.1.2" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">
<MAINGROUP id="OT9rJ2" name="JUCE Network Graphics Demo">


+ 1
- 1
examples/OSCMonitor/OSCMonitor.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="IhmIkj" name="OSCMonitor" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.OSCMonitor" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="N9NMMk" name="OSCMonitor">
<GROUP id="{2B92546C-6B49-72D9-ACD0-0F2FCE9AD0D5}" name="Source">


+ 2
- 3
examples/OSCMonitor/Source/OSCLogListBox.h View File

@@ -128,13 +128,12 @@ public:
else if (arg.isBlob())
{
typeAsString = "blob";
const MemoryBlock& blob = arg.getBlob();
valueAsString = String::fromUTF8( (const char*)blob.getData(), blob.getSize());
auto& blob = arg.getBlob();
valueAsString = String::fromUTF8 ((const char*) blob.getData(), (int) blob.getSize());
}
else
{
typeAsString = "(unknown)";
valueAsString = "";
}
oscLogList.add (getIndentationString (level + 1) + "- " + typeAsString.paddedRight(' ', 12) + valueAsString);


+ 209
- 103
examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java View File

@@ -519,11 +519,18 @@ public class OSCReceiver extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCReceiver.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 0);
}
});
@@ -538,11 +545,18 @@ public class OSCReceiver extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCReceiver.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 1);
}
})
@@ -550,7 +564,7 @@ public class OSCReceiver extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 0);
}
});
@@ -564,11 +578,18 @@ public class OSCReceiver extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCReceiver.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 1);
}
})
@@ -576,7 +597,7 @@ public class OSCReceiver extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 2);
}
})
@@ -584,7 +605,7 @@ public class OSCReceiver extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCReceiver.this.alertDismissed (callback, 0);
}
});
@@ -982,13 +1003,75 @@ public class OSCReceiver extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1011,19 +1094,12 @@ public class OSCReceiver extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1031,6 +1107,89 @@ public class OSCReceiver extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1068,9 +1227,16 @@ public class OSCReceiver extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -1173,13 +1339,20 @@ public class OSCReceiver extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -1201,89 +1374,15 @@ public class OSCReceiver extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -1309,7 +1408,14 @@ public class OSCReceiver extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -1404,7 +1510,7 @@ public class OSCReceiver extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 1
- 1
examples/OSCReceiver/OSCReceiver.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="pdocPt" name="OSCReceiver" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.OSCReceiver" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="Y6Q0O9" name="OSCReceiver">
<GROUP id="{9F303ECD-83DE-CA91-97B4-C083DA897F49}" name="Source">


+ 209
- 103
examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java View File

@@ -519,11 +519,18 @@ public class OSCSender extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCSender.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 0);
}
});
@@ -538,11 +545,18 @@ public class OSCSender extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCSender.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 1);
}
})
@@ -550,7 +564,7 @@ public class OSCSender extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 0);
}
});
@@ -564,11 +578,18 @@ public class OSCSender extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
OSCSender.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 1);
}
})
@@ -576,7 +597,7 @@ public class OSCSender extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 2);
}
})
@@ -584,7 +605,7 @@ public class OSCSender extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
OSCSender.this.alertDismissed (callback, 0);
}
});
@@ -982,13 +1003,75 @@ public class OSCSender extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1011,19 +1094,12 @@ public class OSCSender extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1031,6 +1107,89 @@ public class OSCSender extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1068,9 +1227,16 @@ public class OSCSender extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -1173,13 +1339,20 @@ public class OSCSender extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -1201,89 +1374,15 @@ public class OSCSender extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -1309,7 +1408,14 @@ public class OSCSender extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -1404,7 +1510,7 @@ public class OSCSender extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 1
- 1
examples/OSCSender/OSCSender.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="rysVAr" name="OSCSender" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.OSCSender" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="knnZZJ" name="OSCSender">
<GROUP id="{F2A0007A-4D24-4DD6-DEC8-6428F36CE45D}" name="Source">


+ 1
- 1
examples/OpenGLAppExample/OpenGLAppExample.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="c3KrlE" name="OpenGLAppExample" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.OpenGLAppExample" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="amjEXL" name="OpenGLAppExample">
<GROUP id="{28FE2D12-A88D-07E2-72CF-CD04014CF225}" name="Source">


+ 1
- 1
examples/PluckedStringsDemo/PluckedStringsDemo.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="jKHEJM" name="PluckedStringsDemo" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.PluckedStringsDemo" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="IWdVf7" name="PluckedStringsDemo">
<GROUP id="{8800CD50-6741-8B75-0305-FAF13427EF5D}" name="Source">


+ 1
- 1
examples/PlugInSamples/Arpeggiator/Arpeggiator.jucer View File

@@ -9,7 +9,7 @@
pluginIsMidiEffectPlugin="1" pluginSilenceInIsSilenceOut="0"
pluginEditorRequiresKeys="0" pluginAUExportPrefix="ArpeggiatorAU"
pluginRTASCategory="" aaxIdentifier="com.roli.Arpeggiator" pluginAAXCategory="AAX_EPlugInCategory_Effect"
jucerVersion="5.1.1" companyName="ROLI Ltd." companyWebsite="www.juce.com"
jucerVersion="5.1.2" companyName="ROLI Ltd." companyWebsite="www.juce.com"
companyEmail="info@juce.com" buildAUv3="0" buildStandalone="0"
enableIAA="0" displaySplashScreen="0" reportAppUsage="0" splashScreenColour="Dark"
cppLanguageStandard="11">


+ 4
- 0
examples/PlugInSamples/Arpeggiator/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 1
- 1
examples/PlugInSamples/GainPlugIn/GainPlugIn.jucer View File

@@ -8,7 +8,7 @@
pluginIsSynth="0" pluginWantsMidiIn="0" pluginProducesMidiOut="0"
pluginSilenceInIsSilenceOut="1" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="GainPlugInAU" pluginRTASCategory="" aaxIdentifier="com.roli.GainPlugIn"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.1"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.2"
pluginIsMidiEffectPlugin="0" buildAUv3="0" buildStandalone="0"
enableIAA="0" displaySplashScreen="0" reportAppUsage="0" splashScreenColour="Dark"
companyName="ROLI Ltd." cppLanguageStandard="11">


+ 4
- 0
examples/PlugInSamples/GainPlugIn/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 1
- 1
examples/PlugInSamples/InterAppAudioEffect/InterAppAudioEffect.jucer View File

@@ -9,7 +9,7 @@
pluginIsSynth="0" pluginWantsMidiIn="0" pluginProducesMidiOut="0"
pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0" pluginAUExportPrefix="InterAppAudioEffectAU"
pluginRTASCategory="" aaxIdentifier="com.yourcompany.InterAppAudioEffect"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.1"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.2"
companyName="ROLI Ltd." buildStandalone="1" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" cppLanguageStandard="11">
<MAINGROUP id="BhTVmm" name="InterAppAudioEffect">


+ 4
- 0
examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/AppConfig.h View File

@@ -101,6 +101,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 4
- 0
examples/PlugInSamples/MultiOutSynth/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 1
- 1
examples/PlugInSamples/MultiOutSynth/MultiOutSynth.jucer View File

@@ -9,7 +9,7 @@
pluginSilenceInIsSilenceOut="0" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="MultiOutSynthAU" pluginRTASCategory=""
aaxIdentifier="com.roli.MultiOutSynth" pluginAAXCategory="AAX_ePlugInCategory_SWGenerators"
jucerVersion="5.1.1" companyName="ROLI Ltd." companyWebsite="www.roli.com"
jucerVersion="5.1.2" companyName="ROLI Ltd." companyWebsite="www.roli.com"
companyEmail="info@juce.com" pluginIsMidiEffectPlugin="0" buildAUv3="0"
buildStandalone="0" enableIAA="0" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" cppLanguageStandard="11">


+ 4
- 0
examples/PlugInSamples/NoiseGate/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 1
- 1
examples/PlugInSamples/NoiseGate/NoiseGate.jucer View File

@@ -8,7 +8,7 @@
pluginIsSynth="0" pluginWantsMidiIn="0" pluginProducesMidiOut="0"
pluginSilenceInIsSilenceOut="0" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="NoiseGateAU" pluginRTASCategory="" aaxIdentifier="com.roli.NoiseGate"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.1"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="5.1.2"
pluginIsMidiEffectPlugin="0" buildAUv3="0" buildStandalone="0"
enableIAA="0" displaySplashScreen="0" reportAppUsage="0" splashScreenColour="Dark"
companyName="ROLI Ltd." cppLanguageStandard="11">


+ 4
- 0
examples/PlugInSamples/Surround/JuceLibraryCode/AppConfig.h View File

@@ -103,6 +103,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 1
- 1
examples/PlugInSamples/Surround/Surround.jucer View File

@@ -9,7 +9,7 @@
pluginIsMidiEffectPlugin="0" pluginSilenceInIsSilenceOut="0"
pluginEditorRequiresKeys="0" pluginAUExportPrefix="SurroundAU"
pluginRTASCategory="" aaxIdentifier="com.roli.Surround" pluginAAXCategory="AAX_ePlugInCategory_Dynamics"
jucerVersion="5.1.1" buildAUv3="0" buildStandalone="0" enableIAA="0"
jucerVersion="5.1.2" buildAUv3="0" buildStandalone="0" enableIAA="0"
displaySplashScreen="0" reportAppUsage="0" splashScreenColour="Dark"
companyName="ROLI Ltd." cppLanguageStandard="11">
<MAINGROUP id="dEAH7t" name="Surround">


+ 4
- 0
examples/SimpleFFTExample/JuceLibraryCode/AppConfig.h View File

@@ -174,6 +174,10 @@
//#define JUCE_DSP_USE_STATIC_FFTW 1
#endif
#ifndef JUCE_DSP_ENABLE_SNAP_TO_ZERO
//#define JUCE_DSP_ENABLE_SNAP_TO_ZERO 1
#endif
//==============================================================================
// juce_events flags:


+ 1
- 1
examples/SimpleFFTExample/SimpleFFTExample.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="cgcxPd" name="SimpleFFTExample" projectType="guiapp" version="1.0.0"
bundleIdentifier="com.roli.SimpleFFTExample" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" displaySplashScreen="0" reportAppUsage="0"
jucerVersion="5.1.2" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" companyName="ROLI Ltd." cppLanguageStandard="14">
<MAINGROUP id="rZCHr8" name="SimpleFFTExample">
<GROUP id="{8DC23B3F-98AC-AB1C-B26A-E693AF2DF0D2}" name="Source">


+ 209
- 103
examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java View File

@@ -1448,11 +1448,18 @@ public class JuceDemoPlugin extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
});
@@ -1467,11 +1474,18 @@ public class JuceDemoPlugin extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 1);
}
})
@@ -1479,7 +1493,7 @@ public class JuceDemoPlugin extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
});
@@ -1493,11 +1507,18 @@ public class JuceDemoPlugin extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 1);
}
})
@@ -1505,7 +1526,7 @@ public class JuceDemoPlugin extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 2);
}
})
@@ -1513,7 +1534,7 @@ public class JuceDemoPlugin extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
JuceDemoPlugin.this.alertDismissed (callback, 0);
}
});
@@ -1911,13 +1932,75 @@ public class JuceDemoPlugin extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1940,19 +2023,12 @@ public class JuceDemoPlugin extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1960,6 +2036,89 @@ public class JuceDemoPlugin extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1997,9 +2156,16 @@ public class JuceDemoPlugin extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -2102,13 +2268,20 @@ public class JuceDemoPlugin extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -2130,89 +2303,15 @@ public class JuceDemoPlugin extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -2238,7 +2337,14 @@ public class JuceDemoPlugin extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -2333,7 +2439,7 @@ public class JuceDemoPlugin extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 2
- 0
examples/audio plugin demo/Builds/iOS/Info-AUv3_AppExtension.plist View File

@@ -5,6 +5,8 @@
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone input.</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>


+ 2
- 0
examples/audio plugin demo/Builds/iOS/Info-Standalone_Plugin.plist View File

@@ -5,6 +5,8 @@
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone input.</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CFBundleExecutable</key>


+ 2
- 2
examples/audio plugin demo/JuceDemoPlugin.jucer View File

@@ -8,7 +8,7 @@
pluginProducesMidiOut="1" pluginSilenceInIsSilenceOut="0" pluginTailLength="0"
pluginEditorRequiresKeys="1" pluginAUExportPrefix="JuceDemoProjectAU"
pluginAUViewClass="JuceDemoProjectAU_V1" pluginRTASCategory=""
bundleIdentifier="com.juce.JuceDemoPlugin" jucerVersion="5.1.1"
bundleIdentifier="com.juce.JuceDemoPlugin" jucerVersion="5.1.2"
companyName="ROLI Ltd." aaxIdentifier="com.yourcompany.JuceDemoPlugin"
buildAAX="0" pluginAAXCategory="AAX_ePlugInCategory_Dynamics"
includeBinaryInAppConfig="1" buildVST3="0" pluginManufacturerEmail="support@yourcompany.com"
@@ -107,7 +107,7 @@
</MODULEPATHS>
</LINUX_MAKE>
<XCODE_IPHONE targetFolder="Builds/iOS" iosScreenOrientation="landscape" iosBackgroundAudio="1"
iosBackgroundBle="1">
iosBackgroundBle="1" microphonePermissionNeeded="1">
<CONFIGURATIONS>
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="JuceDemoPlugin"/>
<CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="JuceDemoPlugin"/>


+ 4
- 0
examples/audio plugin demo/JuceLibraryCode/AppConfig.h View File

@@ -101,6 +101,10 @@
//#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 1
#endif
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
//#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 1
#endif
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
//#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 2
- 8
examples/audio plugin demo/Source/PluginEditor.cpp View File

@@ -42,13 +42,7 @@ public:
updateSliderPos();
}
void valueChanged() override
{
if (isMouseButtonDown())
param.setValueNotifyingHost ((float) Slider::getValue());
else
param.setValue ((float) Slider::getValue());
}
void valueChanged() override { param.setValueNotifyingHost ((float) Slider::getValue()); }
void timerCallback() override { updateSliderPos(); }
@@ -63,7 +57,7 @@ public:
const float newValue = param.getValue();
if (newValue != (float) Slider::getValue() && ! isMouseButtonDown())
Slider::setValue (newValue);
Slider::setValue (newValue, NotificationType::dontSendNotification);
}
AudioProcessorParameter& param;


+ 1
- 127
examples/audio plugin demo/Source/PluginProcessor.cpp View File

@@ -26,137 +26,11 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "SinewaveSynth.h"
AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//==============================================================================
/** A demo synth sound that's just a basic sine wave.. */
class SineWaveSound : public SynthesiserSound
{
public:
SineWaveSound() {}
bool appliesToNote (int /*midiNoteNumber*/) override { return true; }
bool appliesToChannel (int /*midiChannel*/) override { return true; }
};
//==============================================================================
/** A simple demo synth voice that just plays a sine wave.. */
class SineWaveVoice : public SynthesiserVoice
{
public:
SineWaveVoice()
{
}
bool canPlaySound (SynthesiserSound* sound) override
{
return dynamic_cast<SineWaveSound*> (sound) != nullptr;
}
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound* /*sound*/,
int /*currentPitchWheelPosition*/) override
{
currentAngle = 0.0;
level = velocity * 0.15;
tailOff = 0.0;
double cyclesPerSecond = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
double cyclesPerSample = cyclesPerSecond / getSampleRate();
angleDelta = cyclesPerSample * 2.0 * double_Pi;
}
void stopNote (float /*velocity*/, bool allowTailOff) override
{
if (allowTailOff)
{
// start a tail-off by setting this flag. The render callback will pick up on
// this and do a fade out, calling clearCurrentNote() when it's finished.
if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the
// stopNote method could be called more than once.
tailOff = 1.0;
}
else
{
// we're being told to stop playing immediately, so reset everything..
clearCurrentNote();
angleDelta = 0.0;
}
}
void pitchWheelMoved (int /*newValue*/) override
{
// can't be bothered implementing this for the demo!
}
void controllerMoved (int /*controllerNumber*/, int /*newValue*/) override
{
// not interested in controllers in this case.
}
void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override
{
processBlock (outputBuffer, startSample, numSamples);
}
void renderNextBlock (AudioBuffer<double>& outputBuffer, int startSample, int numSamples) override
{
processBlock (outputBuffer, startSample, numSamples);
}
private:
template <typename FloatType>
void processBlock (AudioBuffer<FloatType>& outputBuffer, int startSample, int numSamples)
{
if (angleDelta != 0.0)
{
if (tailOff > 0)
{
while (--numSamples >= 0)
{
auto currentSample = static_cast<FloatType> (std::sin (currentAngle) * level * tailOff);
for (int i = outputBuffer.getNumChannels(); --i >= 0;)
outputBuffer.addSample (i, startSample, currentSample);
currentAngle += angleDelta;
++startSample;
tailOff *= 0.99;
if (tailOff <= 0.005)
{
clearCurrentNote();
angleDelta = 0.0;
break;
}
}
}
else
{
while (--numSamples >= 0)
{
auto currentSample = static_cast<FloatType> (std::sin (currentAngle) * level);
for (int i = outputBuffer.getNumChannels(); --i >= 0;)
outputBuffer.addSample (i, startSample, currentSample);
currentAngle += angleDelta;
++startSample;
}
}
}
}
double currentAngle = 0, angleDelta = 0, level = 0, tailOff = 0;
};
//==============================================================================
JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
: AudioProcessor (getBusesProperties())


+ 1
- 1
examples/audio plugin host/Plugin Host.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="NTe0XB0ij" name="Plugin Host" projectType="guiapp" version="1.0.0"
juceFolder="../../../juce" vstFolderMac="~/SDKs/vstsdk2.4" vstFolderPC="c:\SDKs\vstsdk2.4"
bundleIdentifier="com.roli.pluginhost" jucerVersion="5.1.1" companyName="ROLI Ltd."
bundleIdentifier="com.roli.pluginhost" jucerVersion="5.1.2" companyName="ROLI Ltd."
includeBinaryInAppConfig="1" displaySplashScreen="0" reportAppUsage="0"
splashScreenColour="Dark" cppLanguageStandard="11">
<EXPORTFORMATS>


+ 6
- 1
examples/audio plugin host/Source/MainHostWindow.cpp View File

@@ -213,7 +213,12 @@ void MainHostWindow::changeListenerCallback (ChangeBroadcaster* changed)
StringArray MainHostWindow::getMenuBarNames()
{
return { "File", "Plugins", "Options", "Windows" };
StringArray names;
names.add ("File");
names.add ("Plugins");
names.add ("Options");
names.add ("Windows");
return names;
}
PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String& /*menuName*/)


+ 1
- 1
extras/AudioPerformanceTest/AudioPerformanceTest.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="AKfc5m" name="AudioPerformanceTest" projectType="guiapp"
version="1.0.0" bundleIdentifier="com.juce.AudioPerformanceTest"
includeBinaryInAppConfig="1" jucerVersion="5.1.1" displaySplashScreen="0"
includeBinaryInAppConfig="1" jucerVersion="5.1.2" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">
<MAINGROUP id="b1eVTe" name="AudioPerformanceTest">


+ 209
- 103
extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java View File

@@ -1448,11 +1448,18 @@ public class AudioPerformanceTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
});
@@ -1467,11 +1474,18 @@ public class AudioPerformanceTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 1);
}
})
@@ -1479,7 +1493,7 @@ public class AudioPerformanceTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
});
@@ -1493,11 +1507,18 @@ public class AudioPerformanceTest extends Activity
builder.setTitle (title)
.setMessage (message)
.setCancelable (true)
.setOnCancelListener (new DialogInterface.OnCancelListener()
{
public void onCancel (DialogInterface dialog)
{
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
})
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 1);
}
})
@@ -1505,7 +1526,7 @@ public class AudioPerformanceTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 2);
}
})
@@ -1513,7 +1534,7 @@ public class AudioPerformanceTest extends Activity
{
public void onClick (DialogInterface dialog, int id)
{
dialog.cancel();
dialog.dismiss();
AudioPerformanceTest.this.alertDismissed (callback, 0);
}
});
@@ -1911,13 +1932,75 @@ public class AudioPerformanceTest extends Activity
//==============================================================================
public static class HTTPStream
{
public HTTPStream (HttpURLConnection connection_,
int[] statusCode_,
StringBuffer responseHeaders_)
public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse,
String headersToUse, int timeOutMsToUse,
int[] statusCodeToUse, StringBuffer responseHeadersToUse,
int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException
{
connection = connection_;
statusCode = statusCode_;
responseHeaders = responseHeaders_;
isPost = isPostToUse;
postData = postDataToUse;
headers = headersToUse;
timeOutMs = timeOutMsToUse;
statusCode = statusCodeToUse;
responseHeaders = responseHeadersToUse;
totalLength = -1;
numRedirectsToFollow = numRedirectsToFollowToUse;
httpRequestCmd = httpRequestCmdToUse;
connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd);
}
private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData,
String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException
{
HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection());
try
{
newConnection.setInstanceFollowRedirects (false);
newConnection.setConnectTimeout (timeOutMs);
newConnection.setReadTimeout (timeOutMs);
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
newConnection.setRequestProperty (field, value);
}
}
newConnection.setRequestMethod (httpRequestCmd);
if (isPost)
{
newConnection.setDoOutput (true);
if (postData != null)
{
OutputStream out = newConnection.getOutputStream();
out.write(postData);
out.flush();
}
}
return newConnection;
}
catch (Throwable e)
{
newConnection.disconnect();
throw new IOException ("Connection error");
}
}
private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException
@@ -1940,19 +2023,12 @@ public class AudioPerformanceTest extends Activity
try
{
if (connection.getConnectTimeout() > 0)
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS);
else
return streamFuture.get();
return streamFuture.get();
}
catch (InterruptedException e)
{
return null;
}
catch (TimeoutException e)
{
return null;
}
catch (CancellationException e)
{
return null;
@@ -1960,6 +2036,89 @@ public class AudioPerformanceTest extends Activity
}
public final boolean connect()
{
boolean result = false;
int numFollowedRedirects = 0;
while (true)
{
result = doConnect();
if (! result)
return false;
if (++numFollowedRedirects > numRedirectsToFollow)
break;
int status = statusCode[0];
if (status == 301 || status == 302 || status == 303 || status == 307)
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String currentLocation = connection.getURL().toString();
String newLocation = responseHeaders.substring (pos1, pos2);
try
{
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (currentLocation);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != currentLocation)
{
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
synchronized (createStreamLock)
{
if (hasBeenCancelled.get())
return false;
connection.disconnect();
try
{
connection = createConnection (transformedNewLocation, isPost,
postData, headers, timeOutMs,
httpRequestCmd);
}
catch (Throwable e)
{
return false;
}
}
}
else
{
break;
}
}
catch (Throwable e)
{
return false;
}
}
else
{
break;
}
}
else
{
break;
}
}
return result;
}
private final boolean doConnect()
{
synchronized (createStreamLock)
{
@@ -1997,9 +2156,16 @@ public class AudioPerformanceTest extends Activity
{}
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
{
if (entry.getKey() != null && entry.getValue() != null)
responseHeaders.append (entry.getKey() + ": "
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
{
responseHeaders.append(entry.getKey() + ": "
+ android.text.TextUtils.join(",", entry.getValue()) + "\n");
if (entry.getKey().compareTo ("Content-Length") == 0)
totalLength = Integer.decode (entry.getValue().get (0));
}
}
return true;
}
@@ -2102,13 +2268,20 @@ public class AudioPerformanceTest extends Activity
}
public final long getPosition() { return position; }
public final long getTotalLength() { return -1; }
public final long getTotalLength() { return totalLength; }
public final boolean isExhausted() { return false; }
public final boolean setPosition (long newPos) { return false; }
private boolean isPost;
private byte[] postData;
private String headers;
private int timeOutMs;
String httpRequestCmd;
private HttpURLConnection connection;
private int[] statusCode;
private StringBuffer responseHeaders;
private int totalLength;
private int numRedirectsToFollow;
private InputStream inputStream;
private long position;
private final ReentrantLock createStreamLock = new ReentrantLock();
@@ -2130,89 +2303,15 @@ public class AudioPerformanceTest extends Activity
else if (timeOutMs == 0)
timeOutMs = 30000;
// headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines.
// So convert headers string to an array, with an element for each line
String headerLines[] = headers.split("\\n");
for (;;)
{
try
{
HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection());
HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers,
timeOutMs, statusCode, responseHeaders,
numRedirectsToFollow, httpRequestCmd);
if (connection != null)
{
try
{
connection.setInstanceFollowRedirects (false);
connection.setConnectTimeout (timeOutMs);
connection.setReadTimeout (timeOutMs);
// Set request headers
for (int i = 0; i < headerLines.length; ++i)
{
int pos = headerLines[i].indexOf (":");
if (pos > 0 && pos < headerLines[i].length())
{
String field = headerLines[i].substring (0, pos);
String value = headerLines[i].substring (pos + 1);
if (value.length() > 0)
connection.setRequestProperty (field, value);
}
}
connection.setRequestMethod (httpRequestCmd);
if (isPost)
{
connection.setDoOutput (true);
if (postData != null)
{
OutputStream out = connection.getOutputStream();
out.write(postData);
out.flush();
}
}
HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders);
// Process redirect & continue as necessary
int status = statusCode[0];
if (--numRedirectsToFollow >= 0
&& (status == 301 || status == 302 || status == 303 || status == 307))
{
// Assumes only one occurrence of "Location"
int pos1 = responseHeaders.indexOf ("Location:") + 10;
int pos2 = responseHeaders.indexOf ("\n", pos1);
if (pos2 > pos1)
{
String newLocation = responseHeaders.substring(pos1, pos2);
// Handle newLocation whether it's absolute or relative
URL baseUrl = new URL (address);
URL newUrl = new URL (baseUrl, newLocation);
String transformedNewLocation = newUrl.toString();
if (transformedNewLocation != address)
{
address = transformedNewLocation;
// Clear responseHeaders before next iteration
responseHeaders.delete (0, responseHeaders.length());
continue;
}
}
}
return httpStream;
}
catch (Throwable e)
{
connection.disconnect();
}
}
return httpStream;
}
catch (Throwable e) {}
@@ -2238,7 +2337,14 @@ public class AudioPerformanceTest extends Activity
return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath();
}
public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); }
public static final String getDocumentsFolder()
{
if (getAndroidSDKVersion() >= 19)
return getFileLocation ("Documents");
return Environment.getDataDirectory().getAbsolutePath();
}
public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); }
public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); }
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); }
@@ -2333,7 +2439,7 @@ public class AudioPerformanceTest extends Activity
return null;
}
public final int getAndroidSDKVersion()
public static final int getAndroidSDKVersion()
{
return android.os.Build.VERSION.SDK_INT;
}


+ 2
- 2
extras/Projucer/Builds/LinuxMakefile/Makefile View File

@@ -33,7 +33,7 @@ ifeq ($(CONFIG),Debug)
TARGET_ARCH := -march=native
endif
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.1.1 -DJUCE_APP_VERSION_HEX=0x50101 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS)
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.1.2 -DJUCE_APP_VERSION_HEX=0x50102 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS)
JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0
JUCE_TARGET_APP := Projucer
@@ -54,7 +54,7 @@ ifeq ($(CONFIG),Release)
TARGET_ARCH := -march=native
endif
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.1.1 -DJUCE_APP_VERSION_HEX=0x50101 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS)
JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=5.1.2 -DJUCE_APP_VERSION_HEX=0x50102 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS)
JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0
JUCE_TARGET_APP := Projucer


+ 2
- 2
extras/Projucer/Builds/MacOSX/Info-App.plist View File

@@ -33,9 +33,9 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>5.1.1</string>
<string>5.1.2</string>
<key>CFBundleVersion</key>
<string>5.1.1</string>
<string>5.1.2</string>
<key>NSHumanReadableCopyright</key>
<string>ROLI Ltd.</string>
<key>NSHighResolutionCapable</key>


+ 4
- 4
extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj View File

@@ -738,8 +738,8 @@
"_DEBUG=1",
"DEBUG=1",
"JUCER_XCODE_MAC_F6D2F4CF=1",
"JUCE_APP_VERSION=5.1.1",
"JUCE_APP_VERSION_HEX=0x50101",
"JUCE_APP_VERSION=5.1.2",
"JUCE_APP_VERSION_HEX=0x50102",
"JucePlugin_Build_VST=0",
"JucePlugin_Build_VST3=0",
"JucePlugin_Build_AU=0",
@@ -771,8 +771,8 @@
"_NDEBUG=1",
"NDEBUG=1",
"JUCER_XCODE_MAC_F6D2F4CF=1",
"JUCE_APP_VERSION=5.1.1",
"JUCE_APP_VERSION_HEX=0x50101",
"JUCE_APP_VERSION=5.1.2",
"JUCE_APP_VERSION_HEX=0x50102",
"JucePlugin_Build_VST=0",
"JucePlugin_Build_VST3=0",
"JucePlugin_Build_AU=0",


+ 2
- 2
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj View File

@@ -73,7 +73,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -113,7 +113,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>


+ 3
- 3
extras/Projucer/Builds/VisualStudio2013/resources.rc View File

@@ -7,7 +7,7 @@
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,1,0
FILEVERSION 5,1,2,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -15,9 +15,9 @@ BEGIN
BEGIN
VALUE "CompanyName", "ROLI Ltd.\0"
VALUE "FileDescription", "Projucer\0"
VALUE "FileVersion", "5.1.1\0"
VALUE "FileVersion", "5.1.2\0"
VALUE "ProductName", "Projucer\0"
VALUE "ProductVersion", "5.1.1\0"
VALUE "ProductVersion", "5.1.2\0"
END
END


+ 2
- 2
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj View File

@@ -73,7 +73,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -113,7 +113,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2015_78A5022=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>


+ 3
- 3
extras/Projucer/Builds/VisualStudio2015/resources.rc View File

@@ -7,7 +7,7 @@
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,1,0
FILEVERSION 5,1,2,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -15,9 +15,9 @@ BEGIN
BEGIN
VALUE "CompanyName", "ROLI Ltd.\0"
VALUE "FileDescription", "Projucer\0"
VALUE "FileVersion", "5.1.1\0"
VALUE "FileVersion", "5.1.2\0"
VALUE "ProductName", "Projucer\0"
VALUE "ProductVersion", "5.1.1\0"
VALUE "ProductVersion", "5.1.2\0"
END
END


+ 2
- 2
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj View File

@@ -73,7 +73,7 @@
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>
@@ -113,7 +113,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<AdditionalIncludeDirectories>..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.1.1;JUCE_APP_VERSION_HEX=0x50101;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=5.1.2;JUCE_APP_VERSION_HEX=0x50102;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_RTAS=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<PrecompiledHeader/>


+ 3
- 3
extras/Projucer/Builds/VisualStudio2017/resources.rc View File

@@ -7,7 +7,7 @@
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,1,0
FILEVERSION 5,1,2,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -15,9 +15,9 @@ BEGIN
BEGIN
VALUE "CompanyName", "ROLI Ltd.\0"
VALUE "FileDescription", "Projucer\0"
VALUE "FileVersion", "5.1.1\0"
VALUE "FileVersion", "5.1.2\0"
VALUE "ProductName", "Projucer\0"
VALUE "ProductVersion", "5.1.1\0"
VALUE "ProductVersion", "5.1.2\0"
END
END


+ 4
- 3
extras/Projucer/JuceLibraryCode/BinaryData.cpp View File

@@ -1540,9 +1540,9 @@ static const unsigned char temp_binary_data_8[] =
" #endif\r\n"
"}\r\n"
"\r\n"
"bool FILTERCLASSNAME::isMidiEffect () const\r\n"
"bool FILTERCLASSNAME::isMidiEffect() const\r\n"
"{\r\n"
" #ifdef JucePlugin_IsMidiEffect\r\n"
" #if JucePlugin_IsMidiEffect\r\n"
" return true;\r\n"
" #else\r\n"
" return false;\r\n"
@@ -1617,6 +1617,7 @@ static const unsigned char temp_binary_data_8[] =
"\r\n"
"void FILTERCLASSNAME::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)\r\n"
"{\r\n"
" ScopedNoDenormals noDenormals;\r\n"
" const int totalNumInputChannels = getTotalNumInputChannels();\r\n"
" const int totalNumOutputChannels = getTotalNumOutputChannels();\r\n"
"\r\n"
@@ -7028,7 +7029,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw
case 0xafccbd3f: numBytes = 3141; return jucer_AudioComponentTemplate_cpp;
case 0x27c5a93a: numBytes = 1310; return jucer_AudioPluginEditorTemplate_cpp;
case 0x4d0721bf: numBytes = 938; return jucer_AudioPluginEditorTemplate_h;
case 0x51b49ac5: numBytes = 5615; return jucer_AudioPluginFilterTemplate_cpp;
case 0x51b49ac5: numBytes = 5647; return jucer_AudioPluginFilterTemplate_cpp;
case 0x488afa0a: numBytes = 2245; return jucer_AudioPluginFilterTemplate_h;
case 0xabad7041: numBytes = 2151; return jucer_ComponentTemplate_cpp;
case 0xfc72fe86: numBytes = 2064; return jucer_ComponentTemplate_h;


+ 1
- 1
extras/Projucer/JuceLibraryCode/BinaryData.h View File

@@ -33,7 +33,7 @@ namespace BinaryData
const int jucer_AudioPluginEditorTemplate_hSize = 938;
extern const char* jucer_AudioPluginFilterTemplate_cpp;
const int jucer_AudioPluginFilterTemplate_cppSize = 5615;
const int jucer_AudioPluginFilterTemplate_cppSize = 5647;
extern const char* jucer_AudioPluginFilterTemplate_h;
const int jucer_AudioPluginFilterTemplate_hSize = 2245;


+ 2
- 2
extras/Projucer/JuceLibraryCode/JuceHeader.h View File

@@ -34,7 +34,7 @@
namespace ProjectInfo
{
const char* const projectName = "Projucer";
const char* const versionString = "5.1.1";
const int versionNumber = 0x50101;
const char* const versionString = "5.1.2";
const int versionNumber = 0x50102;
}
#endif

+ 1
- 1
extras/Projucer/Projucer.jucer View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="M70qfTRRk" name="Projucer" projectType="guiapp" juceFolder="../../juce"
jucerVersion="5.1.1" version="5.1.1" bundleIdentifier="com.juce.theprojucer"
jucerVersion="5.1.2" version="5.1.2" bundleIdentifier="com.juce.theprojucer"
defines="" includeBinaryInAppConfig="1" splashScreenColour="Dark"
displaySplashScreen="0" reportAppUsage="0" companyName="ROLI Ltd."
cppLanguageStandard="11">


+ 3
- 2
extras/Projucer/Source/BinaryData/jucer_AudioPluginFilterTemplate.cpp View File

@@ -54,9 +54,9 @@ bool FILTERCLASSNAME::producesMidi() const
#endif
}
bool FILTERCLASSNAME::isMidiEffect () const
bool FILTERCLASSNAME::isMidiEffect() const
{
#ifdef JucePlugin_IsMidiEffect
#if JucePlugin_IsMidiEffect
return true;
#else
return false;
@@ -131,6 +131,7 @@ bool FILTERCLASSNAME::isBusesLayoutSupported (const BusesLayout& layouts) const
void FILTERCLASSNAME::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
ScopedNoDenormals noDenormals;
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();


+ 3
- 0
extras/Projucer/Source/Project Saving/jucer_ProjectExport_Android.h View File

@@ -1236,6 +1236,9 @@ private:
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\"" + getJNIActivityClassName() + "\"");
if (androidInAppBillingPermission.get())
defines.set ("JUCE_IN_APP_PURCHASES", "1");
if (supportsGLv3())
defines.set ("JUCE_ANDROID_GL_ES_VERSION_3_0", "1");


+ 3
- 5
extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h View File

@@ -80,12 +80,10 @@ public:
void addWindowsTargetPlatformProperties (PropertyListBuilder& props)
{
static const char* targetPlatformNames[] = { "(default)", "8.1", "10.0.10240.0", "10.0.10586.0", "10.0.14393.0", "10.0.15063.0" };
static const var targetPlatforms[] = { var(), "8.1", "10.0.10240.0", "10.0.10586.0", "10.0.14393.0", "10.0.15063.0" };
if (getWindowsTargetPlatformVersionValue() == Value())
getWindowsTargetPlatformVersionValue() = getDefaultWindowsTargetPlatformVersion();
props.add (new ChoicePropertyComponent (getWindowsTargetPlatformVersionValue(), "Windows Target Platform",
StringArray (targetPlatformNames, numElementsInArray (targetPlatformNames)),
Array<var> (targetPlatforms, numElementsInArray (targetPlatforms))),
props.add (new TextPropertyComponent (getWindowsTargetPlatformVersionValue(), "Windows Target Platform", 20, false),
"Specifies the version of the Windows SDK that will be used when building this project. "
"The default value for this exporter is " + getDefaultWindowsTargetPlatformVersion());
}


+ 3
- 0
extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h View File

@@ -1040,6 +1040,9 @@ public:
s.add ("SEPARATE_STRIP = YES");
}
if (owner.iOS && owner.isInAppPurchasesEnabled())
defines.set ("JUCE_IN_APP_PURCHASES", "1");
defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type));
StringArray defsList;


+ 4
- 0
extras/UnitTestRunner/JuceLibraryCode/AppConfig.h View File

@@ -180,6 +180,10 @@
//#define JUCE_DSP_USE_STATIC_FFTW 1
#endif
#ifndef JUCE_DSP_ENABLE_SNAP_TO_ZERO
//#define JUCE_DSP_ENABLE_SNAP_TO_ZERO 1
#endif
//==============================================================================
// juce_events flags:


+ 1
- 1
extras/UnitTestRunner/UnitTestRunner.jucer View File

@@ -2,7 +2,7 @@
<JUCERPROJECT id="Z2Xzcp" name="UnitTestRunner" projectType="consoleapp" version="1.0.0"
bundleIdentifier="com.roli.UnitTestRunner" includeBinaryInAppConfig="1"
jucerVersion="5.1.1" defines="JUCE_UNIT_TESTS=1" displaySplashScreen="0"
jucerVersion="5.1.2" defines="JUCE_UNIT_TESTS=1" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="14">
<MAINGROUP id="GZdWCU" name="UnitTestRunner">


+ 1
- 1
extras/binarybuilder/BinaryBuilder.jucer View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="3t6YqETY1" name="BinaryBuilder" projectType="consoleapp"
juceFolder="../../../juce" jucerVersion="5.1.1" bundleIdentifier="com.roli.binarybuilder"
juceFolder="../../../juce" jucerVersion="5.1.2" bundleIdentifier="com.roli.binarybuilder"
includeBinaryInAppConfig="1" version="1.0.0" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">


+ 1
- 1
extras/windows dll/jucedll.jucer View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="IvabE4" name="juce_dll" projectType="library" version="1.0.0"
juceLinkage="none" bundleIdentifier="com.roli.jucedll" jucerVersion="5.1.1"
juceLinkage="none" bundleIdentifier="com.roli.jucedll" jucerVersion="5.1.2"
defines="JUCE_DLL_BUILD=1" includeBinaryInAppConfig="1" displaySplashScreen="0"
reportAppUsage="0" splashScreenColour="Dark" companyName="ROLI Ltd."
cppLanguageStandard="11">


+ 17
- 14
modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h View File

@@ -20,8 +20,8 @@
==============================================================================
*/
#pragma once
namespace juce
{
//==============================================================================
/**
@@ -46,14 +46,15 @@ public:
/** Frame rate types. */
enum FrameRateType
{
fps24 = 0,
fps25 = 1,
fps2997 = 2,
fps30 = 3,
fps2997drop = 4,
fps30drop = 5,
fps60 = 6,
fps60drop = 7,
fps23976 = 0,
fps24 = 1,
fps25 = 2,
fps2997 = 3,
fps30 = 4,
fps2997drop = 5,
fps30drop = 6,
fps60 = 7,
fps60drop = 8,
fpsUnknown = 99
};
@@ -70,12 +71,12 @@ public:
/** Time signature denominator, e.g. the 4 of a 3/4 time sig */
int timeSigDenominator;
/** The current play position, in samples from the start of the edit. */
/** The current play position, in samples from the start of the timeline. */
int64 timeInSamples;
/** The current play position, in seconds from the start of the edit. */
/** The current play position, in seconds from the start of the timeline. */
double timeInSeconds;
/** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */
/** For timecode, the position of the start of the timeline, in seconds from 00:00:00:00. */
double editOriginTime;
/** The current play position, in pulses-per-quarter-note. */
@@ -83,7 +84,7 @@ public:
/** The position of the start of the last bar, in pulses-per-quarter-note.
This is the time from the start of the edit to the start of the current
This is the time from the start of the timeline to the start of the current
bar, in ppq units.
Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If
@@ -150,3 +151,5 @@ public:
/** Rewinds the audio. */
virtual void transportRewind() {}
};
} // namespace juce

+ 5
- 0
modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp View File

@@ -20,6 +20,9 @@
==============================================================================
*/
namespace juce
{
AudioChannelSet::AudioChannelSet (uint32 c) : channels (c) {}
AudioChannelSet::AudioChannelSet (const Array<ChannelType>& c)
{
@@ -414,3 +417,5 @@ int32 AudioChannelSet::getWaveChannelMask() const noexcept
return (channels.toInteger() >> 1);
}
} // namespace juce

+ 4
- 2
modules/juce_audio_basics/buffers/juce_AudioChannelSet.h View File

@@ -20,8 +20,8 @@
==============================================================================
*/
#pragma once
namespace juce
{
//==============================================================================
/**
@@ -388,3 +388,5 @@ private:
explicit AudioChannelSet (uint32);
explicit AudioChannelSet (const Array<ChannelType>&);
};
} // namespace juce

+ 7
- 2
modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp View File

@@ -20,6 +20,9 @@
==============================================================================
*/
namespace juce
{
void AudioDataConverters::convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample)
{
const double maxVal = (double) 0x7fff;
@@ -309,7 +312,7 @@ void AudioDataConverters::convertInt24BEToFloat (const void* const source, float
void AudioDataConverters::convertInt32LEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
{
const float scale = 1.0f / 0x7fffffff;
const auto scale = 1.0f / (float) 0x7fffffff;
const char* intData = static_cast<const char*> (source);
if (source != (void*) dest || srcBytesPerSample >= 4)
@@ -334,7 +337,7 @@ void AudioDataConverters::convertInt32LEToFloat (const void* const source, float
void AudioDataConverters::convertInt32BEToFloat (const void* const source, float* const dest, int numSamples, const int srcBytesPerSample)
{
const float scale = 1.0f / 0x7fffffff;
const auto scale = 1.0f / (float) 0x7fffffff;
const char* intData = static_cast<const char*> (source);
if (source != (void*) dest || srcBytesPerSample >= 4)
@@ -596,3 +599,5 @@ public:
static AudioConversionTests audioConversionUnitTests;
#endif
} // namespace juce

+ 4
- 2
modules/juce_audio_basics/buffers/juce_AudioDataConverters.h View File

@@ -20,8 +20,8 @@
==============================================================================
*/
#pragma once
namespace juce
{
//==============================================================================
/**
@@ -708,3 +708,5 @@ private:
AudioDataConverters();
JUCE_DECLARE_NON_COPYABLE (AudioDataConverters)
};
} // namespace juce

+ 30
- 11
modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h View File

@@ -20,8 +20,8 @@
==============================================================================
*/
#pragma once
namespace juce
{
//==============================================================================
/**
@@ -184,11 +184,19 @@ public:
: numChannels (other.numChannels),
size (other.size),
allocatedBytes (other.allocatedBytes),
channels (other.channels),
allocatedData (static_cast<HeapBlock<char, true>&&> (other.allocatedData)),
isClear (other.isClear)
{
memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace));
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
{
channels = preallocatedChannelSpace;
memcpy (preallocatedChannelSpace, other.channels, sizeof (preallocatedChannelSpace));
}
else
{
channels = other.channels;
}
other.numChannels = 0;
other.size = 0;
other.allocatedBytes = 0;
@@ -200,10 +208,19 @@ public:
numChannels = other.numChannels;
size = other.size;
allocatedBytes = other.allocatedBytes;
channels = other.channels;
allocatedData = static_cast<HeapBlock<char, true>&&> (other.allocatedData);
isClear = other.isClear;
memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace));
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace))
{
channels = preallocatedChannelSpace;
memcpy (preallocatedChannelSpace, other.channels, sizeof (preallocatedChannelSpace));
}
else
{
channels = other.channels;
}
other.numChannels = 0;
other.size = 0;
other.allocatedBytes = 0;
@@ -332,7 +349,7 @@ public:
auto numSamplesToCopy = (size_t) jmin (newNumSamples, size);
auto newChannels = reinterpret_cast<Type**> (newData.getData());
auto newChannels = reinterpret_cast<Type**> (newData.get());
auto newChan = reinterpret_cast<Type*> (newData + channelListSize);
for (int j = 0; j < newNumChannels; ++j)
@@ -364,7 +381,7 @@ public:
{
allocatedBytes = newTotalBytes;
allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear);
channels = reinterpret_cast<Type**> (allocatedData.getData());
channels = reinterpret_cast<Type**> (allocatedData.get());
}
auto* chan = reinterpret_cast<Type*> (allocatedData + channelListSize);
@@ -629,7 +646,7 @@ public:
jassert (isPositiveAndBelow (channel, numChannels));
jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size);
const auto increment = (endGain - startGain) / numSamples;
const auto increment = (endGain - startGain) / (float) numSamples;
auto* d = channels[channel] + startSample;
while (--numSamples >= 0)
@@ -1051,7 +1068,7 @@ private:
auto channelListSize = sizeof (Type*) * (size_t) (numChannels + 1);
allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (Type) + channelListSize + 32;
allocatedData.malloc (allocatedBytes);
channels = reinterpret_cast<Type**> (allocatedData.getData());
channels = reinterpret_cast<Type**> (allocatedData.get());
auto* chan = (Type*) (allocatedData + channelListSize);
for (int i = 0; i < numChannels; ++i)
@@ -1076,7 +1093,7 @@ private:
else
{
allocatedData.malloc ((size_t) numChannels + 1, sizeof (Type*));
channels = reinterpret_cast<Type**> (allocatedData.getData());
channels = reinterpret_cast<Type**> (allocatedData.get());
}
for (int i = 0; i < numChannels; ++i)
@@ -1105,3 +1122,5 @@ private:
@see AudioBuffer
*/
typedef AudioBuffer<float> AudioSampleBuffer;
} // namespace juce

+ 10
- 5
modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp View File

@@ -20,6 +20,9 @@
==============================================================================
*/
namespace juce
{
namespace FloatVectorHelpers
{
#define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
@@ -874,7 +877,7 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons
vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier),
JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST, )
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))),
JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mult = Mode::load1 (multiplier);)
@@ -1068,9 +1071,9 @@ public:
#else
// These tests deliberately operate on misaligned memory and will be flagged up by
// checks for undefined behavior!
ValueType* const data1 = addBytesToPointer (buffer1.getData(), random.nextInt (16));
ValueType* const data2 = addBytesToPointer (buffer2.getData(), random.nextInt (16));
int* const int1 = addBytesToPointer (buffer3.getData(), random.nextInt (16));
ValueType* const data1 = addBytesToPointer (buffer1.get(), random.nextInt (16));
ValueType* const data2 = addBytesToPointer (buffer2.get(), random.nextInt (16));
int* const int1 = addBytesToPointer (buffer3.get(), random.nextInt (16));
#endif
fillRandomly (random, data1, num);
@@ -1158,7 +1161,7 @@ public:
static void convertFixed (float* d, const int* s, ValueType multiplier, int num)
{
while (--num >= 0)
*d++ = *s++ * multiplier;
*d++ = (float) *s++ * multiplier;
}
static bool areAllValuesEqual (const ValueType* d, int num, ValueType target)
@@ -1200,3 +1203,5 @@ public:
static FloatVectorOperationsTests vectorOpTests;
#endif
} // namespace juce

+ 34
- 1
modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -20,7 +20,8 @@
==============================================================================
*/
#pragma once
namespace juce
{
#if JUCE_INTEL
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0;
@@ -219,3 +220,35 @@ public:
*/
static void JUCE_CALLTYPE disableDenormalisedNumberSupport() noexcept;
};
//==============================================================================
/**
Helper class providing an RAII-based mechanism for temporarily disabling
denormals on your CPU.
*/
class ScopedNoDenormals
{
public:
inline ScopedNoDenormals() noexcept
{
#if JUCE_USE_SSE_INTRINSICS
mxcsr = _mm_getcsr();
_mm_setcsr (mxcsr | 0x8040); // add the DAZ and FZ bits
#endif
}
inline ~ScopedNoDenormals() noexcept
{
#if JUCE_USE_SSE_INTRINSICS
_mm_setcsr (mxcsr);
#endif
}
private:
#if JUCE_USE_SSE_INTRINSICS
unsigned int mxcsr;
#endif
};
} // namespace juce

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save