From 211ff64e7dbb09f1395c879b294721b12bc9525a Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 5 Dec 2022 23:43:34 +0100 Subject: [PATCH] Prepare for ogg/opus encoding --- libs/ardour/ardour/export_format_base.h | 1 + libs/ardour/ardour/export_formats.h | 26 +++++++++++++++++ libs/ardour/enums.cc | 1 + libs/ardour/export_format_manager.cc | 5 ++++ libs/ardour/export_formats.cc | 37 +++++++++++++++++++++++++ libs/ardour/export_graph_builder.cc | 3 +- 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/libs/ardour/ardour/export_format_base.h b/libs/ardour/ardour/export_format_base.h index 517b3d1ff0..54380c4859 100644 --- a/libs/ardour/ardour/export_format_base.h +++ b/libs/ardour/ardour/export_format_base.h @@ -80,6 +80,7 @@ class LIBARDOUR_API ExportFormatBase { SF_Float = SF_FORMAT_FLOAT, SF_Double = SF_FORMAT_DOUBLE, SF_Vorbis = SF_FORMAT_VORBIS, + SF_Opus = 0x0064, /* SF_FORMAT_OPUS */ SF_MPEG_LAYER_III = 0x0082 /* SF_FORMAT_MPEG_LAYER_III */ }; diff --git a/libs/ardour/ardour/export_formats.h b/libs/ardour/ardour/export_formats.h index 625e1646ea..97cebc10c9 100644 --- a/libs/ardour/ardour/export_formats.h +++ b/libs/ardour/ardour/export_formats.h @@ -355,6 +355,32 @@ public: } }; +class LIBARDOUR_API ExportFormatOggOpus : public ExportFormat, public HasSampleFormat, public HasCodecQuality +{ +public: + ExportFormatOggOpus (); + ~ExportFormatOggOpus (){}; + + bool set_compatibility_state (ExportFormatCompatibility const& compatibility); + + Type get_type () const + { + return T_Sndfile; + } + SampleFormat get_explicit_sample_format () const + { + return SF_Opus; + } + int default_codec_quality () const + { + return 40; + } + virtual bool supports_tagging () const + { + return true; + } +}; + class LIBARDOUR_API ExportFormatMPEG : public ExportFormat, public HasSampleFormat, public HasCodecQuality { public: diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index eda53fada6..7d56fbc3a3 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -652,6 +652,7 @@ setup_enum_writer () REGISTER_CLASS_ENUM (ExportFormatBase, SF_Float); REGISTER_CLASS_ENUM (ExportFormatBase, SF_Double); REGISTER_CLASS_ENUM (ExportFormatBase, SF_Vorbis); + REGISTER_CLASS_ENUM (ExportFormatBase, SF_Opus); REGISTER_CLASS_ENUM (ExportFormatBase, SF_MPEG_LAYER_III); REGISTER (_ExportFormatBase_SampleFormat); diff --git a/libs/ardour/export_format_manager.cc b/libs/ardour/export_format_manager.cc index 3ddde3ad78..cc295f06c2 100644 --- a/libs/ardour/export_format_manager.cc +++ b/libs/ardour/export_format_manager.cc @@ -204,6 +204,11 @@ ExportFormatManager::init_formats () fl_ptr->set_extension ("raw"); add_format (f_ptr); + try { + f_ptr.reset (new ExportFormatOggOpus ()); + add_format (f_ptr); + } catch (ExportFormatIncompatible & e) {} + try { f_ptr.reset (new ExportFormatOggVorbis ()); add_format (f_ptr); diff --git a/libs/ardour/export_formats.cc b/libs/ardour/export_formats.cc index b6cbad0c3a..0c4ece2a68 100644 --- a/libs/ardour/export_formats.cc +++ b/libs/ardour/export_formats.cc @@ -179,6 +179,8 @@ HasSampleFormat::get_sample_format_name (ExportFormatBase::SampleFormat format) return _("8-bit unsigned"); case ExportFormatBase::SF_Vorbis: return _("Vorbis sample format"); + case ExportFormatBase::SF_Opus: + return _("OPUS codec"); case ExportFormatBase::SF_MPEG_LAYER_III: return _("MPEG-2 Audio Layer III"); case ExportFormatBase::SF_None: @@ -382,6 +384,41 @@ ExportFormatBWF::set_compatibility_state (ExportFormatCompatibility const & comp } +/*** OPUS ***/ + +ExportFormatOggOpus::ExportFormatOggOpus () + : HasSampleFormat (sample_formats) +{ + SF_INFO sf_info; + sf_info.channels = 2; + sf_info.samplerate = SR_44_1; + sf_info.format = F_Ogg | SF_Opus; + if (sf_format_check (&sf_info) != SF_TRUE) { + throw ExportFormatIncompatible(); + } + + set_name ("Ogg OPUS"); + set_format_id (F_Ogg); + sample_formats.insert (SF_Opus); + + // 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 ("opus"); + set_quality (Q_LossyCompression); +} + +bool +ExportFormatOggOpus::set_compatibility_state (ExportFormatCompatibility const& compatibility) +{ + bool compatible = compatibility.has_format (F_Ogg); + set_compatible (compatible); + return compatible; +} + /*** MPEG / MP3 ***/ ExportFormatMPEG::ExportFormatMPEG (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 a25fd39734..578432857c 100644 --- a/libs/ardour/export_graph_builder.cc +++ b/libs/ardour/export_graph_builder.cc @@ -345,7 +345,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 || - (format & SF_FORMAT_TYPEMASK) == ExportFormatBase::F_MPEG) { + (format & SF_FORMAT_TYPEMASK) == ExportFormatBase::F_MPEG || + (format & SF_FORMAT_SUBMASK) == ExportFormatBase::SF_Opus) { /* libsndfile uses range 0..1 (worst.. best) for * SFC_SET_VBR_ENCODING_QUALITY and maps * SFC_SET_COMPRESSION_LEVEL = 1.0 - VBR_ENCODING_QUALITY