aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/StreamEncoderOpus.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-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.cpp221
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