Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 9521)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -450,6 +450,7 @@
 	m_current_subsong = 0;
 	m_currentPositionSeconds = 0.0;
 	m_Gain = 1.0f;
+	m_AutoGain = 1.0f;
 	m_ctl_play_at_end = song_end_action::fadeout_song;
 	m_ctl_load_skip_samples = false;
 	m_ctl_load_skip_patterns = false;
@@ -493,6 +494,7 @@
 	for ( const auto & ctl : ctls ) {
 		ctl_set( ctl.first, ctl.second, false );
 	}
+	update_autogain();
 }
 bool module_impl::is_loaded() const {
 	return m_loaded;
@@ -503,7 +505,7 @@
 	std::size_t count_read = 0;
 	while ( count > 0 ) {
 		std::int16_t * const buffers[4] = { left + count_read, right + count_read, rear_left + count_read, rear_right + count_read };
-		AudioReadTargetGainBuffer<std::int16_t> target(*m_Dither, 0, buffers, m_Gain);
+		AudioReadTargetGainBuffer<std::int16_t> target(*m_Dither, 0, buffers, m_Gain * m_AutoGain);
 		std::size_t count_chunk = m_sndFile->Read(
 			static_cast<CSoundFile::samplecount_t>( std::min<std::uint64_t>( count, std::numeric_limits<CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ), // safety margin / samplesize / channels
 			target
@@ -526,7 +528,7 @@
 	std::size_t count_read = 0;
 	while ( count > 0 ) {
 		float * const buffers[4] = { left + count_read, right + count_read, rear_left + count_read, rear_right + count_read };
-		AudioReadTargetGainBuffer<float> target(*m_Dither, 0, buffers, m_Gain);
+		AudioReadTargetGainBuffer<float> target(*m_Dither, 0, buffers, m_Gain * m_AutoGain);
 		std::size_t count_chunk = m_sndFile->Read(
 			static_cast<CSoundFile::samplecount_t>( std::min<std::uint64_t>( count, std::numeric_limits<CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ), // safety margin / samplesize / channels
 			target
@@ -548,7 +550,7 @@
 	m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
 	std::size_t count_read = 0;
 	while ( count > 0 ) {
-		AudioReadTargetGainBuffer<std::int16_t> target(*m_Dither, interleaved + count_read * channels, 0, m_Gain);
+		AudioReadTargetGainBuffer<std::int16_t> target(*m_Dither, interleaved + count_read * channels, 0, m_Gain * m_AutoGain);
 		std::size_t count_chunk = m_sndFile->Read(
 			static_cast<CSoundFile::samplecount_t>( std::min<std::uint64_t>( count, std::numeric_limits<CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ), // safety margin / samplesize / channels
 			target
@@ -570,7 +572,7 @@
 	m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
 	std::size_t count_read = 0;
 	while ( count > 0 ) {
-		AudioReadTargetGainBuffer<float> target(*m_Dither, interleaved + count_read * channels, 0, m_Gain);
+		AudioReadTargetGainBuffer<float> target(*m_Dither, interleaved + count_read * channels, 0, m_Gain * m_AutoGain);
 		std::size_t count_chunk = m_sndFile->Read(
 			static_cast<CSoundFile::samplecount_t>( std::min<std::uint64_t>( count, std::numeric_limits<CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ), // safety margin / samplesize / channels
 			target
@@ -1658,4 +1660,42 @@
 	}
 }
 
+void module_impl::update_autogain() {
+	std::int32_t current_subsong = get_selected_subsong();
+	select_subsong( all_subsongs);
+
+	std::uint64_t samples = Util::Round<std::uint64_t>( get_duration_seconds() * 1000.0 );
+	float buffer[512];
+	auto old_dither = m_Dither->GetMode();
+	m_Dither->SetMode( DitherNone );
+	auto orig_settings = m_sndFile->m_Resampler.m_Settings, new_settings = m_sndFile->m_Resampler.m_Settings;
+	new_settings.emulateAmiga = false;
+	new_settings.SrcMode = SRCMODE_NEAREST;
+	m_sndFile->SetResamplerSettings( new_settings );
+
+	apply_mixer_settings( 1000, 1 );
+	float peak = 0.0f;
+	while ( samples > 0 ) {
+		AudioReadTargetBuffer<float> target(*m_Dither, buffer, nullptr );
+		std::size_t count_chunk = m_sndFile->Read(
+			static_cast<std::uint32_t>( std::min<std::uint64_t>( mpt::size(buffer), samples ) ),
+			target
+		);
+		if(count_chunk == 0) {
+			break;
+		}
+		auto minmax = std::minmax_element( std::begin( buffer ), std::begin( buffer ) + count_chunk );
+		peak = std::max( { peak, mpt::abs(*minmax.first), mpt::abs(*minmax.second) } );
+		samples -= count_chunk;
+	}
+
+	m_Dither->SetMode( old_dither );
+	m_sndFile->SetResamplerSettings( orig_settings );
+	select_subsong( current_subsong );
+
+	if ( peak > 0.0f ) {
+		m_AutoGain = 1.0f / peak;
+	}
+}
+
 } // namespace openmpt
Index: libopenmpt/libopenmpt_impl.hpp
===================================================================
--- libopenmpt/libopenmpt_impl.hpp	(revision 9521)
+++ libopenmpt/libopenmpt_impl.hpp	(working copy)
@@ -98,7 +98,7 @@
 	bool m_loaded;
 	std::unique_ptr<OpenMPT::Dither> m_Dither;
 	subsongs_type m_subsongs;
-	float m_Gain;
+	float m_Gain, m_AutoGain;
 	song_end_action m_ctl_play_at_end;
 	bool m_ctl_load_skip_samples;
 	bool m_ctl_load_skip_patterns;
@@ -126,6 +126,7 @@
 	std::pair< std::string, std::string > format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int command ) const;
 	std::pair< std::string, std::string > format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const;
 	static double could_open_probability( const OpenMPT::FileReader & file, double effort, std::unique_ptr<log_interface> log );
+	void update_autogain();
 public:
 	static std::vector<std::string> get_supported_extensions();
 	static bool is_extension_supported( const char * extension );
