I have a JUCE Project that loads .wav files to an edit and plays the edit in a loop. On Android, it sounds bad on the test device (Samsung Galaxy A33). Playback is very messy and sound crackling occurs. I guess there are some adjustments to be made related to device manager. The only thing I am currently doing in that direction is setting defaultNumInputChannelsToOpen to 0 as I only need output.
Output is attached for emulator and device run. Output also contains some info about the files being played. Actually, playback sounds better in the emulator.
Can you take a read through and see if any of the ideas help your situation?
Particularly reducing the number of CPUs to use and the Android specific code in te::DeviceManager discussed in this post: Default number of input channels - #11 by dave96
@dave96 I tried commenting out the #JUCE_ANDROID code related to “steadyLoadContext” in “tracktion_DeviceManager.h/.cpp” and also set “getNumberOfCPUsToUseForAudio()” to return 1. Unfortunately, the crackling still occurs, tested on a real device (Samsung A33).
I made a very simple Juce GUI app to test this. It just plays back the guitar demo sound from “tracktion_engine/examples/common” on one track.
Everything relevant happens in “MainComponent.h” (apart from the changes in “tracktion_DeviceManager.h/.cpp”):
#pragma once
#include <JuceHeader.h>
/**
* PlaybackDemoAudio.h and PlaybackDemoAudio.cpp contain demo audio data for playback.
* Both files are taken from tracktion_engine/examples/common and put into project folder "Source".
*/
#include "PlaybackDemoAudio.h" //tracktion_engine/examples/common
/*
* Setup namespaces
*/
namespace te = tracktion;
using namespace tracktion::literals;
using namespace std::literals;
/**
* Customize engine behavior by overriding functions from te::EngineBehaviour
*/
class CustomEngineBehaviour: public te::EngineBehaviour
{
public:
bool autoInitialiseDeviceManager() override
{
DBG("Custom behaviour: do not auto-initialise device manager");
return false;
}
te::EngineBehaviour::ClipDefaults getClipDefaults() override
{
auto clip_defaults = te::EngineBehaviour::getClipDefaults();
clip_defaults.useProxyFile = false;
DBG("Custom behaviour: clips use no proxy file");
return clip_defaults;
}
int getNumberOfCPUsToUseForAudio() override
{
DBG("Custom behaviour: Set number of CPUs to 1");
return 1;
}
};
class MainComponent : public juce::Component
{
public:
MainComponent(){
setSize (600, 400);
doPlaybackTest(); //Start testing audio playback here
};
~MainComponent() override;
void paint (juce::Graphics&) override;
void resized() override;
/**
* Code below tests playing audio file as clip inside an edit
*/
std::unique_ptr<te::Engine> engine;
std::unique_ptr<te::Edit> edit;
//=================================================================================================
void doPlaybackTest()
{
//Setup engine with custom behavior and 0 input channels
engine = std::make_unique<te::Engine>(ProjectInfo::projectName, nullptr, std::make_unique<CustomEngineBehaviour>());
engine->getDeviceManager().initialise(0);
//Setup edit for editing
edit = std::make_unique<te::Edit>(*engine, te::createEmptyEdit(*engine), te::Edit::EditRole::forEditing, nullptr, 0);
//Setup file for playback
auto f = juce::File::createTempFile (".ogg");
f.replaceWithData (PlaybackDemoAudio::guitar_loop_ogg, PlaybackDemoAudio::guitar_loop_oggSize);
te::AudioFile audioFile(*engine, f);
//Setup 1 track
edit->ensureNumberOfAudioTracks(1);
te::AudioTrack* track= te::getAudioTracks(*edit)[0];
//Insert clip to track
juce::ReferenceCountedObjectPtr<te::WaveAudioClip> newClip = track->insertWaveClip (f.getFileNameWithoutExtension(), f,
{ { {}, te::TimeDuration::fromSeconds (audioFile.getLength()) }, {} }, false);
//Setup transport
te::TransportControl& transport = edit->getTransport();
transport.looping = false;
transport.setPosition (0s);
//Start playback
transport.play(false);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
Output is attached. “run_with_changes.txt” contains the output of the code presented above. “run_no_changes.txt” contains the output for a version of the project that doesn’t override
getNumberOfCPUsToUseForAudio() and doesn’t comment out the #JUCE_ANDROID code in “tracktion_DeviceManager.h/.cpp”. Both have the sound problem.
I changed the code above to loop around the clip and tried profiling on Android. Screenshots are attached. First one shows results without overriding getNumberOfCPUsToUseForAudio() and commenting out the #JUCE_ANDROID code. Second image shows results after applying the changes.
So does anyone has an idea of what could go wrong for the crackling to appear?
I feel like this very basic tracktion usage example provided above should work as it just plays a demo sound. Might there be something trivial wrong with the settings I am using in the example? Or is it more probable that the problem is rooted in the engine itself?
What’s the “AudioTrack” thread above? Is that the audio thread provided by the Android OS?
I’m not sure I fully understand the profile though, it looks like the Engine based app is only using 12% CPU on average?
Does the audio thread ever peak above the buffer size? It looks pretty even to me.