From 5ff1f28af8dbbc3c030c612c8334a0702c7cae96 Mon Sep 17 00:00:00 2001 From: Mads Kiilerich Date: Thu, 13 Oct 2022 17:25:53 +0200 Subject: [PATCH] Introduce internal MP3 support using libsndfile 1.1.0+ --- libs/ardour/ardour/export_formats.h | 26 +++++++++++++++++++ libs/ardour/export_format_manager.cc | 5 ++++ libs/ardour/export_formats.cc | 38 ++++++++++++++++++++++++++++ libs/ardour/export_graph_builder.cc | 3 ++- libs/ardour/sndfile_helpers.cc | 2 ++ 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/libs/ardour/ardour/export_formats.h b/libs/ardour/ardour/export_formats.h index 04f35e5450..625e1646ea 100644 --- a/libs/ardour/ardour/export_formats.h +++ b/libs/ardour/ardour/export_formats.h @@ -355,6 +355,32 @@ public: } }; +class LIBARDOUR_API ExportFormatMPEG : public ExportFormat, public HasSampleFormat, public HasCodecQuality +{ +public: + ExportFormatMPEG (std::string const& name, std::string const& ext); + ~ExportFormatMPEG (){}; + + bool set_compatibility_state (ExportFormatCompatibility const& compatibility); + + Type get_type () const + { + return T_Sndfile; + } + SampleFormat default_sample_format () const + { + return SF_MPEG_LAYER_III; + } + int default_codec_quality () const + { + return 40; + } + virtual bool supports_tagging () const + { + return true; + } +}; + class LIBARDOUR_API ExportFormatFFMPEG : public ExportFormat, public HasCodecQuality { public: diff --git a/libs/ardour/export_format_manager.cc b/libs/ardour/export_format_manager.cc index 14db27fbf8..3ddde3ad78 100644 --- a/libs/ardour/export_format_manager.cc +++ b/libs/ardour/export_format_manager.cc @@ -218,6 +218,11 @@ ExportFormatManager::init_formats () if (ArdourVideoToolPaths::transcoder_exe (unused, unused)) { f_ptr.reset (new ExportFormatFFMPEG ("MP3", "mp3")); add_format (f_ptr); + } else { + try { + f_ptr.reset (new ExportFormatMPEG ("MP3", "mp3")); + add_format (f_ptr); + } catch (ExportFormatIncompatible & e) {} } } diff --git a/libs/ardour/export_formats.cc b/libs/ardour/export_formats.cc index 6b6fe09e86..b6cbad0c3a 100644 --- a/libs/ardour/export_formats.cc +++ b/libs/ardour/export_formats.cc @@ -382,6 +382,44 @@ ExportFormatBWF::set_compatibility_state (ExportFormatCompatibility const & comp } +/*** MPEG / MP3 ***/ + +ExportFormatMPEG::ExportFormatMPEG (std::string const& name, std::string const& ext) : + HasSampleFormat (sample_formats) +{ + SF_INFO sf_info; + sf_info.channels = 2; + sf_info.samplerate = SR_44_1; + sf_info.format = F_MPEG | SF_MPEG_LAYER_III; + if (sf_format_check (&sf_info) != SF_TRUE) { + throw ExportFormatIncompatible(); + } + + set_name (name); + set_format_id (F_MPEG); + add_sample_format (SF_MPEG_LAYER_III); + + add_endianness (E_FileDefault); + + // libsndfile doesn't expose direct quality control - use these coarse approximations + add_codec_quality ("Low (0%)", 0); + add_codec_quality ("Default (40%)", 40); + add_codec_quality ("High (60%)", 60); + add_codec_quality ("Very High (100%)", 100); + + set_extension (ext); + set_quality (Q_LossyCompression); +} + +bool +ExportFormatMPEG::set_compatibility_state (ExportFormatCompatibility const & compatibility) +{ + bool compatible = compatibility.has_format (F_MPEG); + set_compatible (compatible); + return compatible; +} + + /*** FFMPEG Pipe ***/ ExportFormatFFMPEG::ExportFormatFFMPEG (std::string const& name, std::string const& ext) diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc index 0a785283d0..a25fd39734 100644 --- a/libs/ardour/export_graph_builder.cc +++ b/libs/ardour/export_graph_builder.cc @@ -344,7 +344,8 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr (writer_filename, format, channels, config.format->sample_rate(), config.broadcast_info)); writer->FileWritten.connect_same_thread (copy_files_connection, boost::bind (&ExportGraphBuilder::Encoder::copy_files, this, _1)); - if ((format & SF_FORMAT_SUBMASK) == ExportFormatBase::SF_Vorbis) { + if ((format & SF_FORMAT_SUBMASK) == ExportFormatBase::SF_Vorbis || + (format & SF_FORMAT_TYPEMASK) == ExportFormatBase::F_MPEG) { /* libsndfile uses range 0..1 (worst.. best) for * SFC_SET_VBR_ENCODING_QUALITY and maps * SFC_SET_COMPRESSION_LEVEL = 1.0 - VBR_ENCODING_QUALITY diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc index 0261fa76a4..372036fdc6 100644 --- a/libs/ardour/sndfile_helpers.cc +++ b/libs/ardour/sndfile_helpers.cc @@ -21,6 +21,7 @@ #include #include #include "ardour/sndfile_helpers.h" +#include "ardour/export_format_base.h" using namespace std; @@ -41,6 +42,7 @@ sndfile_data_width (int format) return 32; case SF_FORMAT_FLOAT: case SF_FORMAT_DOUBLE: + case ARDOUR::ExportFormatBase::SF_MPEG_LAYER_III: return 1; /* ridiculous but used as a magic value */ default: // we don't handle anything else within ardour