StreamEncoderAU.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * StreamEncoderAU.cpp
  3. * -------------------
  4. * Purpose: Exporting streamed music files.
  5. * Notes : none
  6. * Authors: Joern Heusipp
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "StreamEncoder.h"
  12. #include "StreamEncoderAU.h"
  13. #include "mpt/io/io.hpp"
  14. #include "mpt/io/io_stdstream.hpp"
  15. #include "Mptrack.h"
  16. #include "TrackerSettings.h"
  17. #include "../common/mptFileIO.h"
  18. OPENMPT_NAMESPACE_BEGIN
  19. class AUStreamWriter : public IAudioStreamEncoder
  20. {
  21. private:
  22. const AUEncoder &enc;
  23. std::ostream &f;
  24. Encoder::Settings settings;
  25. private:
  26. static std::string TagToAnnotation(const std::string & field, const mpt::ustring & tag)
  27. {
  28. if(tag.empty())
  29. {
  30. return std::string();
  31. }
  32. return MPT_AFORMAT("{}={}\n")(field, mpt::ToCharset(mpt::Charset::UTF8, mpt::String::Replace(tag, U_("="), MPT_UTF8("\xEF\xBF\xBD")))); // U+FFFD
  33. }
  34. public:
  35. AUStreamWriter(const AUEncoder &enc_, std::ostream &file, const Encoder::Settings &settings_, const FileTags &tags)
  36. : enc(enc_)
  37. , f(file)
  38. , settings(settings_)
  39. {
  40. MPT_ASSERT(settings.Format.GetSampleFormat().IsValid());
  41. MPT_ASSERT(settings.Samplerate > 0);
  42. MPT_ASSERT(settings.Channels > 0);
  43. std::string annotation;
  44. std::size_t annotationSize = 0;
  45. std::size_t annotationTotalSize = 8;
  46. if(settings.Tags)
  47. {
  48. // same format as invented by sox and implemented by ffmpeg
  49. annotation += TagToAnnotation("title", tags.title);
  50. annotation += TagToAnnotation("artist", tags.artist);
  51. annotation += TagToAnnotation("album", tags.album);
  52. annotation += TagToAnnotation("track", tags.trackno);
  53. annotation += TagToAnnotation("genre", tags.genre);
  54. annotation += TagToAnnotation("comment", tags.comments);
  55. annotationSize = annotation.length() + 1;
  56. annotationTotalSize = annotationSize;
  57. if(settings.Details.AUPaddingAlignHint > 0)
  58. {
  59. annotationTotalSize = mpt::align_up<std::size_t>(24u + annotationTotalSize, settings.Details.AUPaddingAlignHint) - 24u;
  60. }
  61. annotationTotalSize = mpt::align_up<std::size_t>(annotationTotalSize, 8u);
  62. }
  63. MPT_ASSERT(annotationTotalSize >= annotationSize);
  64. MPT_ASSERT(annotationTotalSize % 8 == 0);
  65. mpt::IO::WriteText(f, ".snd");
  66. mpt::IO::WriteIntBE<uint32>(f, mpt::saturate_cast<uint32>(24u + annotationTotalSize));
  67. mpt::IO::WriteIntBE<uint32>(f, ~uint32(0));
  68. uint32 encoding = 0;
  69. if(settings.Format.encoding == Encoder::Format::Encoding::Float)
  70. {
  71. switch(settings.Format.bits)
  72. {
  73. case 32: encoding = 6; break;
  74. case 64: encoding = 7; break;
  75. }
  76. } else if(settings.Format.encoding == Encoder::Format::Encoding::Integer)
  77. {
  78. switch(settings.Format.bits)
  79. {
  80. case 8: encoding = 2; break;
  81. case 16: encoding = 3; break;
  82. case 24: encoding = 4; break;
  83. case 32: encoding = 5; break;
  84. }
  85. } else if(settings.Format.encoding == Encoder::Format::Encoding::Alaw)
  86. {
  87. encoding = 27;
  88. } else if (settings.Format.encoding == Encoder::Format::Encoding::ulaw)
  89. {
  90. encoding = 1;
  91. }
  92. mpt::IO::WriteIntBE<uint32>(f, encoding);
  93. mpt::IO::WriteIntBE<uint32>(f, settings.Samplerate);
  94. mpt::IO::WriteIntBE<uint32>(f, settings.Channels);
  95. if(annotationSize > 0)
  96. {
  97. mpt::IO::WriteText(f, annotation);
  98. mpt::IO::WriteIntBE<uint8>(f, '\0');
  99. }
  100. for(std::size_t i = 0; i < annotationTotalSize - annotationSize; ++i)
  101. {
  102. mpt::IO::WriteIntBE<uint8>(f, '\0');
  103. }
  104. }
  105. SampleFormat GetSampleFormat() const override
  106. {
  107. return settings.Format.GetSampleFormat();
  108. }
  109. void WriteInterleaved(std::size_t frameCount, const double *interleaved) override
  110. {
  111. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  112. }
  113. void WriteInterleaved(std::size_t frameCount, const float *interleaved) override
  114. {
  115. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  116. }
  117. void WriteInterleaved(std::size_t frameCount, const int32 *interleaved) override
  118. {
  119. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  120. }
  121. void WriteInterleaved(std::size_t frameCount, const int24 *interleaved) override
  122. {
  123. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  124. }
  125. void WriteInterleaved(std::size_t frameCount, const int16 *interleaved) override
  126. {
  127. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  128. }
  129. void WriteInterleaved(std::size_t frameCount, const int8 *interleaved) override
  130. {
  131. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  132. }
  133. void WriteInterleaved(std::size_t frameCount, const uint8 *interleaved) override
  134. {
  135. WriteInterleavedBE(f, settings.Channels, settings.Format, frameCount, interleaved);
  136. }
  137. void WriteCues(const std::vector<uint64> &cues) override
  138. {
  139. MPT_UNREFERENCED_PARAMETER(cues);
  140. }
  141. void WriteFinalize() override
  142. {
  143. return;
  144. }
  145. virtual ~AUStreamWriter()
  146. {
  147. return;
  148. }
  149. };
  150. AUEncoder::AUEncoder()
  151. {
  152. Encoder::Traits traits;
  153. traits.fileExtension = P_("au");
  154. traits.fileShortDescription = U_("AU");
  155. traits.fileDescription = U_("NeXT/Sun Audio");
  156. traits.encoderSettingsName = U_("AU");
  157. traits.canTags = true;
  158. traits.canCues = false;
  159. traits.maxChannels = 4;
  160. traits.samplerates = TrackerSettings::Instance().GetSampleRates();
  161. traits.modes = Encoder::ModeLossless;
  162. traits.formats.push_back({ Encoder::Format::Encoding::Float, 64, mpt::endian::big });
  163. traits.formats.push_back({ Encoder::Format::Encoding::Float, 32, mpt::endian::big });
  164. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 32, mpt::endian::big });
  165. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 24, mpt::endian::big });
  166. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 16, mpt::endian::big });
  167. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 8, mpt::endian::big });
  168. traits.formats.push_back({ Encoder::Format::Encoding::Alaw, 16, mpt::endian::big });
  169. traits.formats.push_back({ Encoder::Format::Encoding::ulaw, 16, mpt::endian::big });
  170. traits.defaultSamplerate = 48000;
  171. traits.defaultChannels = 2;
  172. traits.defaultMode = Encoder::ModeLossless;
  173. traits.defaultFormat = { Encoder::Format::Encoding::Float, 32, mpt::endian::big };
  174. SetTraits(traits);
  175. }
  176. bool AUEncoder::IsAvailable() const
  177. {
  178. return true;
  179. }
  180. std::unique_ptr<IAudioStreamEncoder> AUEncoder::ConstructStreamEncoder(std::ostream &file, const Encoder::Settings &settings, const FileTags &tags) const
  181. {
  182. if(!IsAvailable())
  183. {
  184. return nullptr;
  185. }
  186. return std::make_unique<AUStreamWriter>(*this, file, settings, tags);
  187. }
  188. OPENMPT_NAMESPACE_END