Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
800e971
Imported JUCE customizations for Acon Digital products
saagedal Apr 16, 2024
2b03121
Added missing lastFocusChangeCause member in juce_Button class
saagedal Apr 16, 2024
b5b44da
Imported JUCE customizations for Acon Digital products
saagedal Apr 16, 2024
3868997
Added missing lastFocusChangeCause member in juce_Button class
saagedal Apr 16, 2024
b540c17
Imported JUCE customizations for Acon Digital products
saagedal Apr 16, 2024
3b53f99
Added missing lastFocusChangeCause member in juce_Button class
saagedal Apr 16, 2024
a98f9f6
Merge branch 'master' of https://github.com/acondigital/JUCE
saagedal Jul 17, 2024
eaa2cec
Updated Pro Tools version check
saagedal Jul 17, 2024
a8a0c32
Fixed: ARA plug-in should not show up as a plugin variant in AudioSui…
saagedal Sep 13, 2024
e80b89c
Fixed incorrect include statement after updating to ARA 2.3
saagedal Sep 18, 2024
8a969f0
Set highest supported ARA version to 2.3 Final
saagedal Sep 27, 2024
1ca664f
Merge branch 'juce7'
saagedal Dec 30, 2024
a50b1e3
Merge branch 'juce-framework:master' into master
saagedal Dec 31, 2024
c95322f
Merge branch 'juce-framework:master' into master
saagedal Apr 16, 2025
bb1ef3e
Fixed infinite resize loop in Avid Media Composer
saagedal Jun 20, 2025
be481de
Merge branch 'juce-framework:master' into master
saagedal Jul 2, 2025
01a65d2
Merge branch 'juce7'
saagedal Jul 2, 2025
67242b2
Merge branch 'master' of https://github.com/acondigital/JUCE
saagedal Jul 2, 2025
79a308b
Modified JUCE for floating window support
saagedal Jul 16, 2025
7884248
Merge remote-tracking branch 'upstream/master'
saagedal Apr 24, 2026
569d1f0
Fixed potential crashes on Windows
saagedal Apr 24, 2026
6204de6
Commented out MIDI initialisation to avoid assertions
saagedal May 8, 2026
dd36bd6
Merge pull request #2 from acondigital/fix-warnings
saagedal May 8, 2026
0df3dbb
Merge remote-tracking branch 'upstream/master'
saagedal May 20, 2026
81de8a7
Fix duplicate getHighestSupportedApiGeneration; return kARAAPIGenerat…
saagedal May 22, 2026
03c77ea
Return kARAAPIGeneration_2_3_Final for ARA 2.3 partial persistence su…
saagedal May 22, 2026
5a6d5e1
Return kARAAPIGeneration_2_3_Final for ARA 2.3 partial persistence su…
saagedal May 22, 2026
0226f4f
Fix getPlatformSpecificData -> getAudioUnitClient() for JUCE 8.0.13
saagedal May 22, 2026
bf22229
Add ComponentPeer::windowFloatingChild flag for floating child windows
saagedal Jun 30, 2026
4d5f132
Merge pull request #3 from acondigital/add-floating-windows
saagedal Jun 30, 2026
61986e1
Fix VST3 editor reopening in Premiere
lcouka Jul 12, 2026
0edb1cb
Mark Premiere workaround as a quick fix
lcouka Jul 12, 2026
71a4f1c
Remove Premiere editor fallback
lcouka Jul 12, 2026
2844385
Add Audition GDI quick fix
lcouka Jul 12, 2026
14a772e
Simplify Audition renderer selection
lcouka Jul 12, 2026
d557a40
Merge pull request #4 from acondigital/fix/premiere-vst3-editor-reopen
lcouka Jul 13, 2026
12cce55
Merge pull request #5 from acondigital/fix/audition-gdi-quick-fix
lcouka Jul 13, 2026
1005fce
Merge JUCE 8.0.15 into the Acon fork
saagedal Aug 5, 2026
814ef77
Merge pull request #6 from acondigital/merge-8-0-15
saagedal Aug 5, 2026
068b0c9
Fix silent vblank registration failures that froze floating child win…
saagedal Aug 7, 2026
ccc2220
Merge pull request #7 from acondigital/vblank-freeze-fix
saagedal Aug 7, 2026
ab13c6a
Avoid a redundant device-type scan and don't leave a stopped device s…
saagedal Aug 11, 2026
ef241b5
Merge pull request #8 from acondigital/avoid-redundant-device-opens
saagedal Aug 11, 2026
60b1c45
Derive the X11 display scale from the desktop's Xft DPI
saagedal Aug 18, 2026
61ff722
Merge pull request #9 from acondigital/linux-xft-dpi-scaling
saagedal Aug 18, 2026
d8cf0e4
Activate the window when its title bar is clicked
saagedal Aug 20, 2026
813db41
Merge pull request #10 from acondigital/title-bar-click-activation
saagedal Aug 20, 2026
8c0b1df
Restart an unchanged device even when isPlaying() is stale
saagedal Aug 21, 2026
e9edd78
Merge pull request #11 from acondigital/fix-stale-isplaying-on-restart
saagedal Aug 21, 2026
dfc6953
VBlank: remove the flagPaintPending latch that duplicated AsyncUpdate…
saagedal Aug 26, 2026
625aff8
Messaging: dispatch queued messages one at a time so a modal loop can…
saagedal Aug 26, 2026
c75d3bd
Merge pull request #12 from acondigital/modal-loop-message-stranding
saagedal Aug 26, 2026
431068a
VST3: record the classes a plug-in replaces, so a host can follow a m…
saagedal Aug 28, 2026
6aabc80
Merge pull request #13 from acondigital/vst3-host-compatible-classes
saagedal Aug 28, 2026
81471b2
Hand the foreground to another of our windows before destroying one
saagedal Aug 31, 2026
d29fb3d
FileChooser: capture the owner window on the message thread
saagedal Aug 31, 2026
3e51b7b
Merge pull request #14 from acondigital/win-focus-loss-fix
saagedal Aug 31, 2026
34839cc
X11: Accept XDND drags from sources announcing a version newer than 3
saagedal Sep 14, 2026
7523151
Merge pull request #16 from acondigital/x11-xdnd-newer-versions
saagedal Sep 14, 2026
d7da88d
NSViewComponentPeer: Detach a floating child window while it is on an…
saagedal Sep 14, 2026
81f422b
Merge pull request #17 from acondigital/macos-floating-child-other-di…
saagedal Sep 14, 2026
9f48f64
VST3: report each class as discovery reaches it
saagedal Sep 14, 2026
7bd75b4
Merge pull request #18 from acondigital/vst3-discovery-progress
saagedal Sep 14, 2026
9e81b10
Linux: resolve the main executable through /proc/self/exe instead of …
saagedal Sep 14, 2026
549990d
Merge pull request #19 from acondigital/linux-executable-path
saagedal Sep 14, 2026
23af24e
Linux: fix dladdr1 argument order when resolving the main executable
saagedal Sep 14, 2026
4f52370
Merge pull request #20 from acondigital/linux-dladdr1-argument-order
saagedal Sep 14, 2026
f910bd4
LV2: report each bundle once, and rescan a plug-in only when its bund…
saagedal Sep 14, 2026
f9c4ba0
Merge pull request #21 from acondigital/lv2-bundle-scan
saagedal Sep 14, 2026
4e587a8
NSViewComponent: divide the desktop scale out of resizeToFitView to s…
saagedal Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 40 additions & 16 deletions modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,9 @@ static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType
void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>& list)
{
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::shared));
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::exclusive));
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::sharedLowLatency));
// Acon Digital modification - no need for special WASAPI modes
//addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::exclusive));
//addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::sharedLowLatency));
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
Expand Down Expand Up @@ -525,22 +526,23 @@ String AudioDeviceManager::initialiseFromXML (const XmlElement& xml,
if (error.isNotEmpty() && selectDefaultDeviceOnFailure)
error = initialise (numInputChansNeeded, numOutputChansNeeded, nullptr, false, preferredDefaultDeviceName);

enabledMidiInputs.clear();
// Disabled to avoid assert due to initialisation in background thread
//enabledMidiInputs.clear();

const auto midiInputs = [&]
{
Array<MidiDeviceInfo> result;
//const auto midiInputs = [&]
//{
// Array<MidiDeviceInfo> result;

for (auto* c : xml.getChildWithTagNameIterator ("MIDIINPUT"))
result.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") });
// for (auto* c : xml.getChildWithTagNameIterator ("MIDIINPUT"))
// result.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") });

return result;
}();
// return result;
//}();

const MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"),
xml.getStringAttribute ("defaultMidiOutputDevice"));
//const MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"),
// xml.getStringAttribute ("defaultMidiOutputDevice"));

openLastRequestedMidiDevices (midiInputs, defaultOutputDeviceInfo);
//openLastRequestedMidiDevices (midiInputs, defaultOutputDeviceInfo);

return error;
}
Expand Down Expand Up @@ -701,10 +703,17 @@ void AudioDeviceManager::scanDevicesIfNeeded()
{
listNeedsScanning = false;

// Acon Digital modification: createDeviceTypesIfNeeded() already scans every type it
// creates, so only rescan when the types were already there. Scanning twice on the very
// first call costs hundreds of milliseconds on Windows, where it means enumerating (and,
// for ASIO, loading) every installed driver a second time.
const auto deviceTypesAlreadyExisted = availableDeviceTypes.size() > 0;

createDeviceTypesIfNeeded();

for (auto* type : availableDeviceTypes)
type->scanForDevices();
if (deviceTypesAlreadyExisted)
for (auto* type : availableDeviceTypes)
type->scanForDevices();
}
}

Expand Down Expand Up @@ -815,8 +824,23 @@ String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup

if (newSetup != currentSetup)
sendChangeMessage();
else if (currentAudioDevice != nullptr)
else if (currentAudioDevice != nullptr && currentAudioDevice->isOpen())
{
// Acon Digital modification: the setup is unchanged, so there is no need to re-open the
// device - but a caller may have stopped it in order to change the format of the audio it
// is about to play, so make sure it ends up running again rather than silently staying
// stopped. Restarting also gives the callback the audioDeviceAboutToStart() it needs to
// rebuild its converters. A device that is no longer open falls through to the re-open
// path below.
//
// Started unconditionally: stop() clears the callback but leaves the interrupt running,
// clearing the playing flag only when it also tears the IOProc down. isPlaying() can
// therefore be true with no callback attached, which left the device running silent.
// start() is idempotent - it reattaches a callback only when there is none.
currentAudioDevice->start (callbackHandler->getAudioIODeviceCallback());

return {};
}

stopDevice();

Expand Down
100 changes: 99 additions & 1 deletion modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p6p1_REVISION, "JUCE require
#include <AAX_Assert.h>
#include <AAX_TransportTypes.h>

#if JucePlugin_Enable_ARA
#include <ARAAAX.h>
#include <AAX_VARABinding.h>
#endif

JUCE_END_IGNORE_WARNINGS_MSVC
JUCE_END_IGNORE_WARNINGS_GCC_LIKE

Expand Down Expand Up @@ -681,6 +686,14 @@ namespace AAXClasses
void mouseUp (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseUp); }
void mouseDrag (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDrag); }

#if JucePlugin_Enable_ARA
void resized() override
{
if (pluginEditor != nullptr)
pluginEditor->setBounds (getLocalBounds());
}
#endif

void parentSizeChanged() override
{
resizeHostWindow();
Expand Down Expand Up @@ -822,6 +835,14 @@ namespace AAXClasses
return new JuceAAX_Processor();
}

#if JucePlugin_Enable_ARA
AAX_Result Initialize (IACFUnknown* iController) override
{
aaxaraBinding.reset (new ARA::AAX_VARABinding (iController));
return AAX_CEffectParameters::Initialize (iController);
}
#endif

AAX_Result Uninitialize() override
{
cancelPendingUpdate();
Expand All @@ -841,6 +862,36 @@ namespace AAXClasses
AAX_Result EffectInit() override
{
cancelPendingUpdate();

#if JucePlugin_Enable_ARA
ARA::ARAPlugInInstanceRoleFlags knownRoles = 0;
auto result = aaxaraBinding->GetInstanceRoleFlags (&knownRoles, &assignedRoles);

// If no ARA roles provided - work as a regular AAX plug-in
if (result == AAX_SUCCESS)
{
assignedRoles &= (ARA::kARAPlaybackRendererRole | ARA::kARAEditorRendererRole | ARA::kARAEditorViewRole);
if (assignedRoles)
{
result = aaxaraBinding->GetDocumentController (&documentControllerRef);
if (result != AAX_SUCCESS)
return result;

auto araPluginExtension = dynamic_cast<AudioProcessorARAExtension*> (pluginInstance.get());
if (!araPluginExtension)
return AAX_ERROR_NULL_OBJECT;

auto* const plugInEnxtensionInstance = araPluginExtension->bindToARA (documentControllerRef, knownRoles, assignedRoles);
if (!plugInEnxtensionInstance)
return AAX_ERROR_NULL_OBJECT;

result = aaxaraBinding->SetPlugInExtensionInstance (plugInEnxtensionInstance);
if (result != AAX_SUCCESS)
return result;
}
}
#endif

check (Controller()->GetSampleRate (&sampleRate));
processingSidechainChange = false;
auto err = preparePlugin();
Expand Down Expand Up @@ -2284,6 +2335,12 @@ namespace AAXClasses
std::atomic<int> state { 0 };
};

#if JucePlugin_Enable_ARA
std::unique_ptr<ARA::AAX_VARABinding> aaxaraBinding;
ARA::ARADocumentControllerRef documentControllerRef;
ARA::ARAPlugInInstanceRoleFlags assignedRoles;
#endif

RecordingState recordingState;

std::atomic<bool> processingSidechainChange, sidechainDesired;
Expand Down Expand Up @@ -2486,7 +2543,7 @@ namespace AAXClasses

properties->AddProperty (AAX_eProperty_PlugInID_Native, pluginID);

#if ! JucePlugin_AAXDisableAudioSuite
#if ! (JucePlugin_AAXDisableAudioSuite || JucePlugin_Enable_ARA)
properties->AddProperty (AAX_eProperty_PlugInID_AudioSuite,
extensions.getPluginIDForMainBusConfig (fullLayout.getMainInputChannelSet(),
fullLayout.getMainOutputChannelSet(),
Expand Down Expand Up @@ -2548,6 +2605,13 @@ namespace AAXClasses
}
}

#if JucePlugin_Enable_ARA
properties->AddProperty (AAX_eProperty_ShowInMenus, false);
properties->AddProperty (AAX_eProperty_UsesTransport, true);
properties->AddProperty (AAX_eProperty_Constraint_Topology, AAX_eConstraintTopology_Monolithic);
properties->AddPointerProperty (ARA::AAX_eProperty_ARAFactoryPointer, createARAFactory());
#endif

check (desc.AddProcessProc_Native (algorithmProcessCallback, properties));
}

Expand Down Expand Up @@ -2639,6 +2703,35 @@ void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* co
AAXClasses::JuceAAX_Processor::algorithmCallback (instancesBegin, instancesEnd);
}

static bool HostDeclaresARASupport(AAX_ICollection* inCollection)
{
bool result = false;
const AAX_IDescriptionHost* const hostDesc = inCollection->DescriptionHost();
if (hostDesc)
{
std::unique_ptr<const AAX_IFeatureInfo> featureInfo(hostDesc->AcquireFeatureProperties(AAXATTR_ClientFeature_ARA));
if (featureInfo)
{
AAX_ESupportLevel featureSupportLevel = AAX_eSupportLevel_Uninitialized;
const AAX_Result err = featureInfo->SupportLevel(featureSupportLevel);
AAX_TRACE_RELEASE(kAAX_Trace_Priority_Normal, "ARA initialization: host support for ARA: %s, err: %ld",
AAX::AsStringSupportLevel(featureSupportLevel).c_str(), (long int)err);
result = (err == AAX_SUCCESS) && (featureSupportLevel == AAX_eSupportLevel_Supported);
}
else
{
AAX_TRACE_RELEASE(kAAX_Trace_Priority_Normal, "ARA initialization: Unable to query AAXATTR_ClientFeature_ARA");
result = false;
}
}
else
{
AAX_TRACE_RELEASE(kAAX_Trace_Priority_High, "ARA initialization: AAX_IDescriptionHost is null");
result = false;
}
return result;
}

//==============================================================================
AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*);
AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection)
Expand All @@ -2652,6 +2745,11 @@ AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection)

if (auto* descriptor = collection->NewDescriptor())
{
#if JucePlugin_Enable_ARA
if (!HostDeclaresARASupport(collection))
return AAX_SUCCESS;
#endif

AAXClasses::getPlugInDescription (*descriptor, stemFormatFeatureInfo.get());
collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,22 @@ class JuceVST3EditController final : public Vst::EditController,

void createEditor (AudioProcessor& plugin)
{
pluginEditor.reset (plugin.createEditorAndMakeActive());
// Acon Digital modification - Quick fix, may be fixed in a newer JUCE version (> 8.0.13).
if (detail::PluginUtilities::getHostType().isPremiere())
if (auto* active = plugin.getActiveEditor())
{
auto* preflight = dynamic_cast<ContentWrapperComponent*> (active->getParentComponent());
if (preflight != nullptr && preflight->pluginEditor.get() == active)
{
active->setHostContext (nullptr);
preflight->editorHostContext.reset();
pluginEditor = std::move (preflight->pluginEditor);
}
}

if (pluginEditor == nullptr)
pluginEditor.reset (plugin.createEditorAndMakeActive());
// Acon Digital modification - End of modification

#if JucePlugin_Enable_ARA
jassert (pluginEditor->getARAClientExtensions() != nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ namespace juce
*/
class JUCE_API AudioUnitPluginFormat : public AudioUnitPluginFormatHeadless
{
public:
//==============================================================================
/** Attempts to reload an AU plugin's state from some preset file data.

@see VSTPluginFormat::loadFromFXBFile
*/
static bool setStateFromAUPresetFile (AudioPluginInstance*, const MemoryBlock&);

//==============================================================================
/** Attempts to save an AU plugin's state to some preset file data.

@see VSTPluginFormat::saveToFXBFile
*/
static bool saveStateToAUPresetFile (AudioPluginInstance*, MemoryBlock&);

private:
void createPluginInstance (const PluginDescription&, double, int, PluginCreationCallback) override;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,74 @@ bool hasEditor() const override
createAudioUnitPluginInstance<AudioUnitPluginInstance> (*this, desc, rate, blockSize, callback);
}

bool AudioUnitPluginFormat::setStateFromAUPresetFile (AudioPluginInstance* api, const MemoryBlock& rawData)
{
auto* auClient = api->getAudioUnitClient();
jassert (auClient != nullptr);
AudioUnit audioUnit = auClient->getAudioUnitHandle();

CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy (kCFAllocatorDefault, (const UInt8*) rawData.getData(),
rawData.getSize(), kCFAllocatorNull);
CFReadStreamOpen (stream);

CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
CFPropertyListRef propertyList = CFPropertyListCreateFromStream (kCFAllocatorDefault, stream, 0,
kCFPropertyListImmutable, &format, 0);
CFRelease (stream);

if (propertyList != 0)
{
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global,
0, &propertyList, sizeof (propertyList));

AudioUnitParameter param;
param.mAudioUnit = audioUnit;
param.mParameterID = kAUParameterListener_AnyParameter;

AUParameterListenerNotify (nullptr, nullptr, &param);

CFRelease (propertyList);
return true;
}

return false;
}

bool AudioUnitPluginFormat::saveStateToAUPresetFile (AudioPluginInstance* api, MemoryBlock& rawData)
{
auto* auClient = api->getAudioUnitClient();
jassert (auClient != nullptr);
AudioUnit audioUnit = auClient->getAudioUnitHandle();

CFPropertyListRef propertyList = 0;
UInt32 sz = sizeof (CFPropertyListRef);

if (AudioUnitGetProperty (audioUnit,
kAudioUnitProperty_ClassInfo,
kAudioUnitScope_Global,
0, &propertyList, &sz) == noErr)
{
CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers (kCFAllocatorDefault, kCFAllocatorDefault);
CFWriteStreamOpen (stream);

CFIndex bytesWritten = CFPropertyListWriteToStream (propertyList, stream, kCFPropertyListBinaryFormat_v1_0, 0);
CFWriteStreamClose (stream);

CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten);

rawData.setSize ((size_t) bytesWritten);
rawData.copyFrom (CFDataGetBytePtr (data), 0, bytesWritten);
CFRelease (data);

CFRelease (stream);
CFRelease (propertyList);

return true;
}

return false;
}

} // namespace juce

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -825,4 +825,4 @@ void VSTPluginFormat::createPluginInstance (const PluginDescription& desc,

} // namespace juce

#endif
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ FileSearchPath LV2PluginFormatHeadless::getDefaultLocationsToSearch()
return pimpl->getDefaultLocationsToSearch();
}

StringArray LV2PluginFormatHeadless::getPluginUrisInBundle (const String& bundlePath)
{
return pimpl->getPluginUrisInBundle (bundlePath);
}

bool LV2PluginFormatHeadless::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const
{
return false;
Expand Down
Loading
Loading