Files
foobar2000-sdk/foobar2000/SDK/replaygain.cpp
2021-12-14 00:28:25 -07:00

226 lines
5.9 KiB
C++

#include "foobar2000.h"
void t_replaygain_config::reset()
{
m_source_mode = source_mode_none;
m_processing_mode = processing_mode_none;
m_preamp_without_rg = 0;
m_preamp_with_rg = 0;
}
audio_sample t_replaygain_config::query_scale(const file_info & info) const
{
return query_scale(info.get_replaygain());
}
audio_sample t_replaygain_config::query_scale(const replaygain_info & info) const {
const audio_sample peak_margin = 1.0;//used to be 0.999 but it must not trigger on lossless
audio_sample peak = peak_margin;
audio_sample gain = 0;
bool have_rg_gain = false, have_rg_peak = false;
if (m_source_mode == source_mode_track || m_source_mode == source_mode_album)
{
if (m_source_mode == source_mode_track)
{
if (info.is_track_gain_present()) {gain = info.m_track_gain; have_rg_gain = true; }
else if (info.is_album_gain_present()) {gain = info.m_album_gain; have_rg_gain = true; }
if (info.is_track_peak_present()) {peak = info.m_track_peak; have_rg_peak = true; }
else if (info.is_album_peak_present()) {peak = info.m_album_peak; have_rg_peak = true; }
}
else
{
if (info.is_album_gain_present()) {gain = info.m_album_gain; have_rg_gain = true; }
else if (info.is_track_gain_present()) {gain = info.m_track_gain; have_rg_gain = true; }
if (info.is_album_peak_present()) {peak = info.m_album_peak; have_rg_peak = true; }
else if (info.is_track_peak_present()) {peak = info.m_track_peak; have_rg_peak = true; }
}
}
gain += have_rg_gain ? m_preamp_with_rg : m_preamp_without_rg;
audio_sample scale = 1.0;
if (m_processing_mode == processing_mode_gain || m_processing_mode == processing_mode_gain_and_peak)
{
scale *= audio_math::gain_to_scale(gain);
}
if ((m_processing_mode == processing_mode_peak || m_processing_mode == processing_mode_gain_and_peak) && have_rg_peak)
{
if (scale * peak > peak_margin)
scale = (audio_sample)(peak_margin / peak);
}
return scale;
}
audio_sample t_replaygain_config::query_scale(const metadb_handle_ptr & p_object) const
{
return query_scale(p_object->get_async_info_ref()->info());
}
audio_sample replaygain_manager::core_settings_query_scale(const file_info & p_info)
{
t_replaygain_config temp;
get_core_settings(temp);
return temp.query_scale(p_info);
}
audio_sample replaygain_manager::core_settings_query_scale(const metadb_handle_ptr & info)
{
t_replaygain_config temp;
get_core_settings(temp);
return temp.query_scale(info);
}
//enum t_source_mode {source_mode_none,source_mode_track,source_mode_album};
//enum t_processing_mode {processing_mode_none,processing_mode_gain,processing_mode_gain_and_peak,processing_mode_peak};
namespace {
class format_dbdelta
{
public:
format_dbdelta(double p_val);
operator const char*() const {return m_buffer;}
private:
pfc::string_fixed_t<128> m_buffer;
};
static const char * querysign(int val) {
return val<0 ? "-" : val>0 ? "+" : "\xc2\xb1";
}
format_dbdelta::format_dbdelta(double p_val) {
int val = (int)(p_val * 10);
m_buffer << querysign(val) << (abs(val)/10) << "." << (abs(val)%10) << "dB";
}
}
void t_replaygain_config::format_name(pfc::string_base & p_out) const
{
switch(m_processing_mode)
{
case processing_mode_none:
p_out = "None.";
break;
case processing_mode_gain:
switch(m_source_mode)
{
case source_mode_none:
if (m_preamp_without_rg == 0) p_out = "None.";
else p_out = PFC_string_formatter() << "Preamp : " << format_dbdelta(m_preamp_without_rg);
break;
case source_mode_track:
{
pfc::string_formatter fmt;
fmt << "Apply track gain";
if (m_preamp_without_rg != 0 || m_preamp_with_rg != 0) fmt << ", with preamp";
fmt << ".";
p_out = fmt;
}
break;
case source_mode_album:
{
pfc::string_formatter fmt;
fmt << "Apply album gain";
if (m_preamp_without_rg != 0 || m_preamp_with_rg != 0) fmt << ", with preamp";
fmt << ".";
p_out = fmt;
}
break;
};
break;
case processing_mode_gain_and_peak:
switch(m_source_mode)
{
case source_mode_none:
if (m_preamp_without_rg >= 0) p_out = "None.";
else p_out = PFC_string_formatter() << "Preamp : " << format_dbdelta(m_preamp_without_rg);
break;
case source_mode_track:
{
pfc::string_formatter fmt;
fmt << "Apply track gain";
if (m_preamp_without_rg != 0 || m_preamp_with_rg != 0) fmt << ", with preamp";
fmt << ", prevent clipping according to track peak.";
p_out = fmt;
}
break;
case source_mode_album:
{
pfc::string_formatter fmt;
fmt << "Apply album gain";
if (m_preamp_without_rg != 0 || m_preamp_with_rg != 0) fmt << ", with preamp";
fmt << ", prevent clipping according to album peak.";
p_out = fmt;
}
break;
};
break;
case processing_mode_peak:
switch(m_source_mode)
{
case source_mode_none:
p_out = "None.";
break;
case source_mode_track:
p_out = "Prevent clipping according to track peak.";
break;
case source_mode_album:
p_out = "Prevent clipping according to album peak.";
break;
};
break;
}
}
bool t_replaygain_config::is_active() const
{
switch(m_processing_mode)
{
case processing_mode_none:
return false;
case processing_mode_gain:
switch(m_source_mode)
{
case source_mode_none:
return m_preamp_without_rg != 0;
case source_mode_track:
return true;
case source_mode_album:
return true;
};
return false;
case processing_mode_gain_and_peak:
switch(m_source_mode)
{
case source_mode_none:
return m_preamp_without_rg < 0;
case source_mode_track:
return true;
case source_mode_album:
return true;
};
return false;
case processing_mode_peak:
switch(m_source_mode)
{
case source_mode_none:
return false;
case source_mode_track:
return true;
case source_mode_album:
return true;
};
return false;
default:
return false;
}
}
replaygain_scanner::ptr replaygain_scanner_entry::instantiate( uint32_t flags ) {
replaygain_scanner_entry_v2::ptr p2;
if ( p2 &= this ) return p2->instantiate( flags );
else return instantiate();
}