329 lines
9.7 KiB
C
329 lines
9.7 KiB
C
|
/*
|
||
|
* StreamEncoder.h
|
||
|
* ---------------
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "openmpt/all/BuildSettings.hpp"
|
||
|
|
||
|
#include "mpt/base/bit.hpp"
|
||
|
#include "openmpt/soundbase/SampleFormat.hpp"
|
||
|
#include "../soundlib/Tagging.h"
|
||
|
|
||
|
#include <iosfwd>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_BEGIN
|
||
|
|
||
|
|
||
|
|
||
|
inline constexpr int opus_bitrates [] = {
|
||
|
8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384, 448, 510
|
||
|
};
|
||
|
inline constexpr int vorbis_bitrates [] = {
|
||
|
32, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 500
|
||
|
};
|
||
|
inline constexpr int layer3_bitrates [] = {
|
||
|
8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320
|
||
|
};
|
||
|
inline constexpr int mpeg1layer3_bitrates [] = {
|
||
|
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
|
||
|
};
|
||
|
inline constexpr uint32 opus_samplerates [] = {
|
||
|
48000,
|
||
|
24000, 16000,
|
||
|
12000, 8000
|
||
|
};
|
||
|
inline constexpr uint32 opus_all_samplerates [] = {
|
||
|
48000, 44100, 32000,
|
||
|
24000, 22050, 16000,
|
||
|
12000, 11025, 8000
|
||
|
};
|
||
|
inline constexpr uint32 vorbis_samplerates [] = {
|
||
|
48000, 44100, 32000,
|
||
|
24000, 22050, 16000,
|
||
|
12000, 11025, 8000
|
||
|
};
|
||
|
inline constexpr uint32 layer3_samplerates [] = {
|
||
|
48000, 44100, 32000,
|
||
|
24000, 22050, 16000
|
||
|
};
|
||
|
inline constexpr uint32 mpeg1layer3_samplerates [] = {
|
||
|
48000, 44100, 32000
|
||
|
};
|
||
|
|
||
|
|
||
|
namespace Encoder
|
||
|
{
|
||
|
|
||
|
enum Mode
|
||
|
{
|
||
|
ModeCBR = 1<<0,
|
||
|
ModeABR = 1<<1,
|
||
|
ModeVBR = 1<<2,
|
||
|
ModeQuality = 1<<3,
|
||
|
ModeLossless = 1<<4,
|
||
|
ModeInvalid = 0
|
||
|
};
|
||
|
|
||
|
struct Format
|
||
|
{
|
||
|
enum class Encoding
|
||
|
{
|
||
|
Float = 1,
|
||
|
Integer = 2,
|
||
|
Alaw = 3,
|
||
|
ulaw = 4,
|
||
|
Unsigned = 5,
|
||
|
};
|
||
|
Encoding encoding;
|
||
|
uint8 bits;
|
||
|
mpt::endian endian;
|
||
|
bool operator==(const Format &other) const
|
||
|
{
|
||
|
return encoding == other.encoding && bits == other.bits && endian == other.endian;
|
||
|
}
|
||
|
bool operator!=(const Format& other) const
|
||
|
{
|
||
|
return encoding != other.encoding || bits != other.bits || endian != other.endian;
|
||
|
}
|
||
|
int32 AsInt() const
|
||
|
{
|
||
|
return (static_cast<int32>(endian == mpt::endian::little) << 16) | (static_cast<int32>(encoding) << 8) | static_cast<int32>(bits);
|
||
|
}
|
||
|
static Format FromInt(int32 val)
|
||
|
{
|
||
|
Encoder::Format f;
|
||
|
f.bits = val & 0xff;
|
||
|
f.encoding = static_cast<Encoder::Format::Encoding>((val >> 8) & 0xff);
|
||
|
f.endian = ((val >> 16) & 0xff) ? mpt::endian::little : mpt::endian::big;
|
||
|
return f;
|
||
|
}
|
||
|
SampleFormat GetSampleFormat() const
|
||
|
{
|
||
|
SampleFormat result = SampleFormat::Invalid;
|
||
|
switch(encoding)
|
||
|
{
|
||
|
case Encoding::Float:
|
||
|
switch(bits)
|
||
|
{
|
||
|
case 32:
|
||
|
result = SampleFormat::Float32;
|
||
|
break;
|
||
|
case 64:
|
||
|
result = SampleFormat::Float64;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case Encoding::Integer:
|
||
|
switch(bits)
|
||
|
{
|
||
|
case 8:
|
||
|
result = SampleFormat::Int8;
|
||
|
break;
|
||
|
case 16:
|
||
|
result = SampleFormat::Int16;
|
||
|
break;
|
||
|
case 24:
|
||
|
result = SampleFormat::Int24;
|
||
|
break;
|
||
|
case 32:
|
||
|
result = SampleFormat::Int32;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case Encoding::Alaw:
|
||
|
switch (bits)
|
||
|
{
|
||
|
case 16:
|
||
|
result = SampleFormat::Int16;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case Encoding::ulaw:
|
||
|
switch (bits)
|
||
|
{
|
||
|
case 16:
|
||
|
result = SampleFormat::Int16;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case Encoding::Unsigned:
|
||
|
switch (bits)
|
||
|
{
|
||
|
case 8:
|
||
|
result = SampleFormat::Unsigned8;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct Traits
|
||
|
{
|
||
|
|
||
|
mpt::PathString fileExtension;
|
||
|
mpt::ustring fileShortDescription;
|
||
|
mpt::ustring encoderSettingsName;
|
||
|
|
||
|
mpt::ustring fileDescription;
|
||
|
|
||
|
bool canTags = false;
|
||
|
std::vector<mpt::ustring> genres;
|
||
|
int modesWithFixedGenres = 0;
|
||
|
|
||
|
bool canCues = false;
|
||
|
|
||
|
int maxChannels = 0;
|
||
|
std::vector<uint32> samplerates;
|
||
|
|
||
|
int modes = Encoder::ModeInvalid;
|
||
|
std::vector<int> bitrates;
|
||
|
std::vector<Format> formats;
|
||
|
|
||
|
uint32 defaultSamplerate = 48000;
|
||
|
uint16 defaultChannels = 2;
|
||
|
|
||
|
Encoder::Mode defaultMode = Encoder::ModeInvalid;
|
||
|
int defaultBitrate = 0;
|
||
|
float defaultQuality = 0.0f;
|
||
|
Format defaultFormat = { Encoder::Format::Encoding::Float, 32, mpt::endian::little };
|
||
|
int defaultDitherType = 1;
|
||
|
};
|
||
|
|
||
|
struct StreamSettings
|
||
|
{
|
||
|
int32 FLACCompressionLevel = 5; // 8
|
||
|
uint32 AUPaddingAlignHint = 4096;
|
||
|
uint32 MP3ID3v2MinPadding = 1024;
|
||
|
uint32 MP3ID3v2PaddingAlignHint = 4096;
|
||
|
bool MP3ID3v2WriteReplayGainTXXX = true;
|
||
|
int32 MP3LameQuality = 3; // 0
|
||
|
bool MP3LameID3v2UseLame = false;
|
||
|
bool MP3LameCalculateReplayGain = true;
|
||
|
bool MP3LameCalculatePeakSample = true;
|
||
|
int32 OpusComplexity = -1; // 10
|
||
|
};
|
||
|
|
||
|
struct Settings
|
||
|
{
|
||
|
|
||
|
bool Cues;
|
||
|
bool Tags;
|
||
|
|
||
|
uint32 Samplerate;
|
||
|
uint16 Channels;
|
||
|
|
||
|
Encoder::Mode Mode;
|
||
|
int Bitrate;
|
||
|
float Quality;
|
||
|
Encoder::Format Format;
|
||
|
int Dither;
|
||
|
|
||
|
StreamSettings Details;
|
||
|
|
||
|
};
|
||
|
|
||
|
} // namespace Encoder
|
||
|
|
||
|
|
||
|
class IAudioStreamEncoder
|
||
|
{
|
||
|
protected:
|
||
|
IAudioStreamEncoder() { }
|
||
|
public:
|
||
|
virtual ~IAudioStreamEncoder() = default;
|
||
|
public:
|
||
|
virtual SampleFormat GetSampleFormat() const = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const double *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const float *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const int32 *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const int24 *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const int16 *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const int8 *interleaved) = 0;
|
||
|
virtual void WriteInterleaved(std::size_t frameCount, const uint8 *interleaved) = 0;
|
||
|
virtual void WriteCues(const std::vector<uint64> &cues) = 0; // optional
|
||
|
virtual void WriteFinalize() = 0;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const double *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const float *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int32 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int24 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int16 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int8 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedLE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const uint8 *interleaved);
|
||
|
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const double *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const float *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int32 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int24 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int16 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const int8 *interleaved);
|
||
|
std::pair<bool, std::size_t> WriteInterleavedBE(std::ostream &f, uint16 channels, Encoder::Format format, std::size_t frameCount, const uint8 *interleaved);
|
||
|
|
||
|
|
||
|
|
||
|
class StreamWriterBase
|
||
|
: public IAudioStreamEncoder
|
||
|
{
|
||
|
protected:
|
||
|
std::ostream &f;
|
||
|
std::streampos fStart;
|
||
|
std::vector<char> buf;
|
||
|
public:
|
||
|
StreamWriterBase(std::ostream &stream);
|
||
|
virtual ~StreamWriterBase();
|
||
|
public:
|
||
|
SampleFormat GetSampleFormat() const override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const double *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const float *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const int32 *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const int24 *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const int16 *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const int8 *interleaved) override;
|
||
|
void WriteInterleaved(std::size_t frameCount, const uint8 *interleaved) override;
|
||
|
void WriteCues(const std::vector<uint64> &cues) override;
|
||
|
void WriteFinalize() override;
|
||
|
protected:
|
||
|
void WriteBuffer();
|
||
|
};
|
||
|
|
||
|
|
||
|
class EncoderFactoryBase
|
||
|
{
|
||
|
private:
|
||
|
Encoder::Traits m_Traits;
|
||
|
protected:
|
||
|
EncoderFactoryBase() { }
|
||
|
virtual ~EncoderFactoryBase() = default;
|
||
|
void SetTraits(const Encoder::Traits &traits);
|
||
|
public:
|
||
|
virtual std::unique_ptr<IAudioStreamEncoder> ConstructStreamEncoder(std::ostream &file, const Encoder::Settings &settings, const FileTags &tags) const = 0;
|
||
|
const Encoder::Traits &GetTraits() const
|
||
|
{
|
||
|
return m_Traits;
|
||
|
}
|
||
|
virtual bool IsBitrateSupported(int samplerate, int channels, int bitrate) const;
|
||
|
virtual mpt::ustring DescribeQuality(float quality) const;
|
||
|
virtual mpt::ustring DescribeBitrateVBR(int bitrate) const;
|
||
|
virtual mpt::ustring DescribeBitrateABR(int bitrate) const;
|
||
|
virtual mpt::ustring DescribeBitrateCBR(int bitrate) const;
|
||
|
virtual bool IsAvailable() const = 0;
|
||
|
};
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_END
|