StreamEncoderFLAC.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * StreamEncoder.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 "StreamEncoderFLAC.h"
  13. #include "Mptrack.h"
  14. #include "TrackerSettings.h"
  15. #include <FLAC/metadata.h>
  16. #include <FLAC/format.h>
  17. #include <FLAC/stream_encoder.h>
  18. OPENMPT_NAMESPACE_BEGIN
  19. class FLACStreamWriter : public StreamWriterBase
  20. {
  21. private:
  22. const FLACEncoder &enc;
  23. Encoder::Settings settings;
  24. FLAC__StreamMetadata *flac_metadata[1];
  25. FLAC__StreamEncoder *encoder;
  26. std::vector<FLAC__int32> sampleBuf;
  27. private:
  28. static FLAC__StreamEncoderWriteStatus FLACWriteCallback(const FLAC__StreamEncoder *flacenc, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
  29. {
  30. return reinterpret_cast<FLACStreamWriter*>(client_data)->WriteCallback(flacenc, buffer, bytes, samples, current_frame);
  31. }
  32. static FLAC__StreamEncoderSeekStatus FLACSeekCallback(const FLAC__StreamEncoder *flacenc, FLAC__uint64 absolute_byte_offset, void *client_data)
  33. {
  34. return reinterpret_cast<FLACStreamWriter*>(client_data)->SeekCallback(flacenc, absolute_byte_offset);
  35. }
  36. static FLAC__StreamEncoderTellStatus FLACTellCallback(const FLAC__StreamEncoder *flacenc, FLAC__uint64 *absolute_byte_offset, void *client_data)
  37. {
  38. return reinterpret_cast<FLACStreamWriter*>(client_data)->TellCallback(flacenc, absolute_byte_offset);
  39. }
  40. FLAC__StreamEncoderWriteStatus WriteCallback(const FLAC__StreamEncoder *flacenc, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
  41. {
  42. MPT_UNREFERENCED_PARAMETER(flacenc);
  43. MPT_UNREFERENCED_PARAMETER(samples);
  44. MPT_UNREFERENCED_PARAMETER(current_frame);
  45. f.write(reinterpret_cast<const char*>(buffer), bytes);
  46. if(!f) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
  47. return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
  48. }
  49. FLAC__StreamEncoderSeekStatus SeekCallback(const FLAC__StreamEncoder *flacenc, FLAC__uint64 absolute_byte_offset)
  50. {
  51. MPT_UNREFERENCED_PARAMETER(flacenc);
  52. f.seekp(absolute_byte_offset);
  53. if(!f) return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
  54. return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
  55. }
  56. FLAC__StreamEncoderTellStatus TellCallback(const FLAC__StreamEncoder *flacenc, FLAC__uint64 *absolute_byte_offset)
  57. {
  58. MPT_UNREFERENCED_PARAMETER(flacenc);
  59. if(absolute_byte_offset)
  60. {
  61. *absolute_byte_offset = f.tellp();
  62. }
  63. if(!f) return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
  64. return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
  65. }
  66. private:
  67. void AddCommentField(const std::string &field, const mpt::ustring &data)
  68. {
  69. if(!field.empty() && !data.empty())
  70. {
  71. FLAC__StreamMetadata_VorbisComment_Entry entry;
  72. FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, field.c_str(), mpt::ToCharset(mpt::Charset::UTF8, data).c_str());
  73. FLAC__metadata_object_vorbiscomment_append_comment(flac_metadata[0], entry, false);
  74. }
  75. }
  76. public:
  77. FLACStreamWriter(const FLACEncoder &enc_, std::ostream &stream, const Encoder::Settings &settings_, const FileTags &tags)
  78. : StreamWriterBase(stream)
  79. , enc(enc_)
  80. , settings(settings_)
  81. {
  82. flac_metadata[0] = nullptr;
  83. encoder = nullptr;
  84. MPT_ASSERT(settings.Format.GetSampleFormat().IsValid());
  85. MPT_ASSERT(settings.Samplerate > 0);
  86. MPT_ASSERT(settings.Channels > 0);
  87. encoder = FLAC__stream_encoder_new();
  88. FLAC__stream_encoder_set_channels(encoder, settings.Channels);
  89. FLAC__stream_encoder_set_bits_per_sample(encoder, settings.Format.GetSampleFormat().GetBitsPerSample());
  90. FLAC__stream_encoder_set_sample_rate(encoder, settings.Samplerate);
  91. int compressionLevel = settings.Details.FLACCompressionLevel;
  92. FLAC__stream_encoder_set_compression_level(encoder, compressionLevel);
  93. if(settings.Tags)
  94. {
  95. flac_metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
  96. AddCommentField("ENCODER", tags.encoder);
  97. AddCommentField("SOURCEMEDIA", U_("tracked music file"));
  98. AddCommentField("TITLE", tags.title );
  99. AddCommentField("ARTIST", tags.artist );
  100. AddCommentField("ALBUM", tags.album );
  101. AddCommentField("DATE", tags.year );
  102. AddCommentField("COMMENT", tags.comments );
  103. AddCommentField("GENRE", tags.genre );
  104. AddCommentField("CONTACT", tags.url );
  105. AddCommentField("BPM", tags.bpm ); // non-standard
  106. AddCommentField("TRACKNUMBER", tags.trackno );
  107. FLAC__stream_encoder_set_metadata(encoder, flac_metadata, 1);
  108. }
  109. FLAC__stream_encoder_init_stream(encoder, FLACWriteCallback, FLACSeekCallback, FLACTellCallback, nullptr, this);
  110. }
  111. SampleFormat GetSampleFormat() const
  112. {
  113. return settings.Format.GetSampleFormat();
  114. }
  115. template <typename Tsample>
  116. void WriteInterleavedInt(std::size_t frameCount, const Tsample *p)
  117. {
  118. MPT_ASSERT(settings.Format.GetSampleFormat() == SampleFormatTraits<Tsample>::sampleFormat());
  119. sampleBuf.resize(frameCount * settings.Channels);
  120. for(std::size_t frame = 0; frame < frameCount; ++frame)
  121. {
  122. for(int channel = 0; channel < settings.Channels; ++channel)
  123. {
  124. sampleBuf[frame * settings.Channels + channel] = *p;
  125. p++;
  126. }
  127. }
  128. while(frameCount > 0)
  129. {
  130. unsigned int frameCountChunk = mpt::saturate_cast<unsigned int>(frameCount);
  131. FLAC__stream_encoder_process_interleaved(encoder, sampleBuf.data(), frameCountChunk);
  132. frameCount -= frameCountChunk;
  133. }
  134. }
  135. void WriteInterleaved(std::size_t frameCount, const int8 *interleaved) override
  136. {
  137. WriteInterleavedInt(frameCount, interleaved);
  138. }
  139. void WriteInterleaved(std::size_t frameCount, const int16 *interleaved) override
  140. {
  141. WriteInterleavedInt(frameCount, interleaved);
  142. }
  143. void WriteInterleaved(std::size_t frameCount, const int24 *interleaved) override
  144. {
  145. WriteInterleavedInt(frameCount, interleaved);
  146. }
  147. void WriteFinalize() override
  148. {
  149. FLAC__stream_encoder_finish(encoder);
  150. }
  151. virtual ~FLACStreamWriter()
  152. {
  153. FLAC__stream_encoder_delete(encoder);
  154. encoder = nullptr;
  155. if(flac_metadata[0])
  156. {
  157. FLAC__metadata_object_delete(flac_metadata[0]);
  158. flac_metadata[0] = nullptr;
  159. }
  160. }
  161. };
  162. FLACEncoder::FLACEncoder()
  163. {
  164. Encoder::Traits traits;
  165. traits.fileExtension = P_("flac");
  166. traits.fileShortDescription = U_("FLAC");
  167. traits.fileDescription = U_("Free Lossless Audio Codec");
  168. traits.encoderSettingsName = U_("FLAC");
  169. traits.canTags = true;
  170. traits.maxChannels = 4;
  171. traits.samplerates = TrackerSettings::Instance().GetSampleRates();
  172. traits.modes = Encoder::ModeLossless;
  173. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 24, mpt::get_endian() });
  174. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 16, mpt::get_endian() });
  175. traits.formats.push_back({ Encoder::Format::Encoding::Integer, 8, mpt::get_endian() });
  176. traits.defaultSamplerate = 48000;
  177. traits.defaultChannels = 2;
  178. traits.defaultMode = Encoder::ModeLossless;
  179. traits.defaultFormat = { Encoder::Format::Encoding::Integer, 24, mpt::get_endian() };
  180. SetTraits(traits);
  181. }
  182. bool FLACEncoder::IsAvailable() const
  183. {
  184. return true;
  185. }
  186. std::unique_ptr<IAudioStreamEncoder> FLACEncoder::ConstructStreamEncoder(std::ostream &file, const Encoder::Settings &settings, const FileTags &tags) const
  187. {
  188. if(!IsAvailable())
  189. {
  190. return nullptr;
  191. }
  192. return std::make_unique<FLACStreamWriter>(*this, file, settings, tags);
  193. }
  194. OPENMPT_NAMESPACE_END