Rendered file is very loud

Hi,

I’m trying to render an edit to file. It sort of works but the rendered file sounds very different from what I’m hearing when playing back the edit. In particular:

  • Muted tracks are still included in the rendered file. (Do I need to exclude them from tracksToDo in the call to renderToFile?)
  • Volumes are very loud, leading to distortion

Any tips for where to look?

Erik

How are you rendering?
Muted tracks shouldn’t be included and it shouldn’t be very loud…

        te::Edit* theSong = this->song.get();
        te::EditTimeRange range{ START_TIME, theSong->getLength() };
        juce::BigInteger tracksToDo{ 0 };
        for (auto i = 0; i < te::getAllTracks(*theSong).size(); i++)
            tracksToDo.setBit(i);
        
        result = te::Renderer::renderToFile("Bounce", file, *theSong, range, tracksToDo, true, {}, true);

I have several MIDI tracks that are routed to a single audio track where the synth plugin lives. Should I include these tracks into tracksToDo?

Yeah, usually you’d want all the tracks.
That looks ok to me… I don’t really understand this line though? te::Edit* theSong = this->song.get();

Yeah, usually you’d want all the tracks.

Ok.

That looks ok to me…

Thanks, ok, then at least I know that I have to look elsewhere… perhaps the volumes aren’t set the way I think etc.

I don’t really understand this line though?

Yeah, it looks a bit weird out of context. :smiley: It has to do with how the function is called. In this case I guess I could have just referenced song rather than assigning a new pointer. In any case it seems unlikely that it would be related to the quality of the rendered audio file :smile:

No but in my experience code smells like that often point to other issues that can affect the one in hand so it’s always worth asking about.

I’d double check your levels, especially the master level.

Well I don’t even have a volume plugin on the master – or is there always an implicit volume plugin?

Just to be sure, I refactored the function to get rid of the this thing. I also added some logging:


// This is the button handler
void MainComponent::renderSongCallback() {
    JUCE_ASSERT_MESSAGE_THREAD
    
    renderDialog = std::make_unique<FileChooser> ("Bounce to disk",
                                               File::getSpecialLocation (File::userHomeDirectory),
                                               "*.wav");
    
    auto folderChooserFlags = FileBrowserComponent::saveMode | FileBrowserComponent::warnAboutOverwriting;
    
    renderDialog->launchAsync (folderChooserFlags, [this] (const FileChooser& chooser)
   {
       File file (chooser.getResult());
       internalBounceSongToFile(file);
   });
}

// Do the actual work
bool MainComponent::internalBounceSongToFile(const juce::File& file) {
    const ScopedLock lock (songLock);
    
    te::EditTimeRange range{ START_TIME, song->getLength() };
    juce::BigInteger tracksToDo{ 0 };
    
    for (auto i = 0; i < te::getAllTracks(*song).size(); i++) {
        auto *at = te::getAudioTracks (*song)[i];
        if (at == nullptr) {
            juce::Logger::writeToLog("Track " + juce::String(i) + " is null");
        } else {
            auto *vol = at->getVolumePlugin();
            juce::Logger::writeToLog(at->getName() + " " + juce::String(vol->getVolumeDb()) + " " + (at->isMuted(false) ? "muted" : "playing"));
            tracksToDo.setBit(i);
        }
    }
    
    return te::Renderer::renderToFile("Bounce", file, *song, range, tracksToDo, true, {}, true);
}

I muted all the tracks and when starting playback, nothing is heard (as expected). Rendering the file still seem to render all tracks though.

Here is the log output:

Song Click -100 muted
Synth 0-14 0 muted
Synth 15-29 0 muted
Audio 0 -0.710763 muted
Audio 1 1.53713 muted
Audio 2 0 muted
Audio 3 0 muted
Backing 0 (drums) 0 muted
Backing 1 0 muted
Backing 2 0 muted
MIDI 0 0 muted
MIDI 1 0 muted
MIDI 2 0 muted
MIDI 3 0 muted
MIDI 4 0 muted
MIDI 5 0 muted
MIDI 6 0 muted
MIDI 7 0 muted
MIDI 8 0 muted
Track 19 is null
Track 20 is null
Track 21 is null
Track 22 is null
Track 23 is null

I’m not sure how to interpret the null tracks, are they printed because there are non-audio tracks present? Could that be a clue to what is going on?

    for (auto i = 0; i < te::getAllTracks(*song).size(); i++) {
        auto *at = te::getAudioTracks (*song)[i];

Your index i will range over all tracks, but you’re using it to index into an array of only the audio tracks, so some of them are out of range, and that’s where your nullptrs come from. Get modern and try range based for loops instead. :slight_smile:

Re: the levels, some audio devices let you get away with playing back audio that goes above 1.0 by compressing it to avoid it sounding distorted. So it could be just that your mix is too loud and will get clipped when flattened into a wav file, but sounds OK when you render it live.

After spending a couple of hours on this problem, I suddenly realised that I might have misinterpreted your answer: I thought you were saying “that shouldn’t happen” but what you were actually saying was that I shouldn’t include the muted tracks when calling renderToFile! Correct?

This indeed seems to have been the case. At first this seemed unlikely as I was only playing back an audio file without changing the volume plugin. But it turned out that the culprit was a reverb plugin – for some reason the built-in reverb multiplies the dry gain value by 2, so my gain setting of 1.0 meant that the dry signal was doubled in gain.

This increased signal still played back fine on CoreAudio, probably because of some internal compression/limitation as you said.