diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp new file mode 100644 index 00000000..e7926d6c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp @@ -0,0 +1,221 @@ +/* + * StreamEncoderOpus.cpp + * --------------------- + * Purpose: Exporting streamed music files. + * Notes : none + * Authors: Joern Heusipp + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" + +#include "StreamEncoder.h" +#include "StreamEncoderOpus.h" + +#include <sstream> + +#include "Mptrack.h" + +#include <deque> + +#if defined(MPT_WITH_OPUS) && defined(MPT_WITH_OPUSENC) +#include <opusenc.h> +#endif + + +OPENMPT_NAMESPACE_BEGIN + + + +static Encoder::Traits BuildTraits() + { + Encoder::Traits traits; +#if defined(MPT_WITH_OPUS) && defined(MPT_WITH_OPUSENC) + traits.fileExtension = P_("opus"); + traits.fileShortDescription = U_("Opus"); + traits.fileDescription = U_("Ogg Opus"); + traits.encoderSettingsName = U_("Opus"); + traits.canTags = true; + traits.maxChannels = 4; + traits.samplerates = mpt::make_vector(opus_all_samplerates); + traits.modes = Encoder::ModeCBR | Encoder::ModeVBR; + traits.bitrates = mpt::make_vector(opus_bitrates); + traits.defaultSamplerate = 48000; + traits.defaultChannels = 2; + traits.defaultMode = Encoder::ModeVBR; + traits.defaultBitrate = 128; +#endif + return traits; + } + + + +#if defined(MPT_WITH_OPUS) && defined(MPT_WITH_OPUSENC) + +class OpusStreamWriter : public StreamWriterBase +{ +private: + OpusEncCallbacks ope_callbacks; + OggOpusComments *ope_comments; + OggOpusEnc *ope_encoder; + std::vector<std::pair<std::string, std::string> > opus_comments; +private: + static int CallbackWrite(void *user_data, const unsigned char *ptr, opus_int32 len) + { + return reinterpret_cast<OpusStreamWriter*>(user_data)->CallbackWriteImpl(ptr, len); + } + static int CallbackClose(void *user_data) + { + return reinterpret_cast<OpusStreamWriter*>(user_data)->CallbackCloseImpl(); + } + int CallbackWriteImpl(const unsigned char *ptr, opus_int32 len) + { + if(len < 0) + { + return 1; + } + if(!ptr && len > 0) + { + return 1; + } + buf.assign(ptr, ptr + len); + WriteBuffer(); + return 0; + } + int CallbackCloseImpl() + { + return 0; + } +private: + void AddCommentField(const std::string &field, const mpt::ustring &data) + { + if(!field.empty() && !data.empty()) + { + opus_comments.push_back(std::make_pair(field, mpt::ToCharset(mpt::Charset::UTF8, data))); + } + } +public: + OpusStreamWriter(std::ostream &stream, const Encoder::Settings &settings, const FileTags &tags) + : StreamWriterBase(stream) + { + ope_callbacks.write = &CallbackWrite; + ope_callbacks.close = &CallbackClose; + opus_comments.clear(); + + bool opus_cbr = (settings.Mode == Encoder::ModeCBR); + int opus_bitrate = settings.Bitrate * 1000; + + if(settings.Tags) + { + AddCommentField("ENCODER", tags.encoder); + AddCommentField("SOURCEMEDIA", U_("tracked music file")); + AddCommentField("TITLE", tags.title ); + AddCommentField("ARTIST", tags.artist ); + AddCommentField("ALBUM", tags.album ); + AddCommentField("DATE", tags.year ); + AddCommentField("COMMENT", tags.comments ); + AddCommentField("GENRE", tags.genre ); + AddCommentField("CONTACT", tags.url ); + AddCommentField("BPM", tags.bpm ); // non-standard + AddCommentField("TRACKNUMBER", tags.trackno ); + } + + int ope_error = 0; + + ope_comments = ope_comments_create(); + if(settings.Tags && ope_comments) + { + for(const auto & comment : opus_comments) + { + ope_comments_add(ope_comments, comment.first.c_str(), comment.second.c_str()); + } + } + + ope_encoder = ope_encoder_create_callbacks(&ope_callbacks, this, ope_comments, settings.Samplerate, settings.Channels, settings.Channels > 2 ? 1 : 0, &ope_error); + + opus_int32 ctl_serial = mpt::random<uint32>(theApp.PRNG()); + ope_encoder_ctl(ope_encoder, OPE_SET_SERIALNO(ctl_serial)); + + opus_int32 ctl_bitrate = opus_bitrate; + ope_encoder_ctl(ope_encoder, OPUS_SET_BITRATE(ctl_bitrate)); + + if(opus_cbr) + { + opus_int32 ctl_vbr = 0; + ope_encoder_ctl(ope_encoder, OPUS_SET_VBR(ctl_vbr)); + } else + { + opus_int32 ctl_vbr = 1; + ope_encoder_ctl(ope_encoder, OPUS_SET_VBR(ctl_vbr)); + opus_int32 ctl_vbrcontraint = 0; + ope_encoder_ctl(ope_encoder, OPUS_SET_VBR_CONSTRAINT(ctl_vbrcontraint)); + } + + opus_int32 complexity = settings.Details.OpusComplexity; + if(complexity >= 0) + { + ope_encoder_ctl(ope_encoder, OPUS_SET_COMPLEXITY(complexity)); + } + + ope_encoder_flush_header(ope_encoder); + + } + void WriteInterleaved(size_t count, const float *interleaved) override + { + while(count > 0) + { + ope_encoder_write_float(ope_encoder, interleaved, mpt::saturate_cast<int>(count)); + count -= static_cast<size_t>(mpt::saturate_cast<int>(count)); + } + } + void WriteFinalize() override + { + ope_encoder_drain(ope_encoder); + } + virtual ~OpusStreamWriter() + { + ope_encoder_destroy(ope_encoder); + ope_encoder = NULL; + + ope_comments_destroy(ope_comments); + ope_comments = NULL; + } +}; + +#endif // MPT_WITH_OGG + + + +OggOpusEncoder::OggOpusEncoder() +{ + SetTraits(BuildTraits()); +} + + +bool OggOpusEncoder::IsAvailable() const +{ +#if defined(MPT_WITH_OPUS) && defined(MPT_WITH_OPUSENC) + return true; +#else + return false; +#endif +} + + +std::unique_ptr<IAudioStreamEncoder> OggOpusEncoder::ConstructStreamEncoder(std::ostream &file, const Encoder::Settings &settings, const FileTags &tags) const +{ + if(!IsAvailable()) + { + return nullptr; + } +#if defined(MPT_WITH_OPUS) && defined(MPT_WITH_OPUSENC) + return std::make_unique<OpusStreamWriter>(file, settings, tags); +#else + return nullptr; +#endif +} + + + +OPENMPT_NAMESPACE_END |