Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "flacencoder.h"
24 :
25 : #include <algorithm>
26 : #include <vector>
27 :
28 : #include "FLAC++/encoder.h"
29 :
30 : #include "../dsp/audiomathutils.h"
31 :
32 : #include "global/io/iodevice.h"
33 :
34 : #include "log.h"
35 :
36 : namespace muse::audio::encode {
37 : class FlacHandler final : public FLAC::Encoder::Stream
38 : {
39 : public:
40 0 : explicit FlacHandler(io::IODevice& outDev)
41 0 : : m_outDev{&outDev}
42 : {
43 0 : DO_ASSERT(m_outDev);
44 0 : }
45 :
46 : protected:
47 0 : FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], const size_t bytes, uint32_t, uint32_t) override
48 : {
49 0 : if (m_outDev->write(buffer, bytes) != bytes) {
50 0 : return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
51 : }
52 :
53 0 : return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
54 : }
55 :
56 0 : FLAC__StreamEncoderSeekStatus seek_callback(const FLAC__uint64 absolute_byte_offset) override
57 : {
58 0 : if (!m_outDev->seek(absolute_byte_offset)) {
59 0 : return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
60 : }
61 :
62 0 : return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
63 : }
64 :
65 0 : FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64* absolute_byte_offset) override
66 : {
67 0 : *absolute_byte_offset = m_outDev->pos();
68 0 : return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
69 : }
70 :
71 : private:
72 : io::IODevice* m_outDev;
73 : };
74 :
75 0 : FlacEncoder::FlacEncoder(const SoundTrackFormat& format, io::IODevice& dstDevice)
76 0 : : AbstractAudioEncoder(format), m_flac{std::make_unique<FlacHandler>(dstDevice)}
77 : {
78 0 : }
79 :
80 0 : FlacEncoder::~FlacEncoder() noexcept = default;
81 :
82 0 : bool FlacEncoder::begin(const samples_t totalSamplesNumber)
83 : {
84 0 : int bitsPerSample = 0;
85 0 : switch (m_format.sampleFormat) {
86 0 : case AudioSampleFormat::Int16:
87 0 : bitsPerSample = 16;
88 0 : break;
89 0 : case AudioSampleFormat::Int24:
90 0 : bitsPerSample = 24;
91 0 : break;
92 0 : default:
93 0 : return false;
94 : }
95 :
96 0 : if (!m_flac->set_verify(true)
97 0 : || !m_flac->set_compression_level(0)
98 0 : || !m_flac->set_channels(m_format.outputSpec.audioChannelCount)
99 0 : || !m_flac->set_sample_rate(m_format.outputSpec.sampleRate)
100 0 : || !m_flac->set_bits_per_sample(bitsPerSample)
101 0 : || !m_flac->set_total_samples_estimate(totalSamplesNumber)) {
102 0 : return false;
103 : }
104 :
105 : FLAC__StreamMetadata_VorbisComment_Entry entry;
106 : FLAC__StreamMetadata* metadata[2];
107 0 : metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
108 0 : metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
109 0 : FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist");
110 0 : FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/ false);
111 0 : FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984");
112 0 : FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/ false);
113 :
114 0 : metadata[1]->length = 1234; /* set the padding length */
115 0 : m_flac->set_metadata(metadata, 2);
116 :
117 0 : if (m_flac->init() != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
118 0 : return false;
119 : }
120 :
121 0 : return true;
122 : }
123 :
124 0 : size_t FlacEncoder::encode(const samples_t samplesPerChannel, const float* input)
125 : {
126 0 : int bitsPerSample = 0;
127 0 : switch (m_format.sampleFormat) {
128 0 : case AudioSampleFormat::Int16:
129 0 : bitsPerSample = 16;
130 0 : break;
131 0 : case AudioSampleFormat::Int24:
132 0 : bitsPerSample = 24;
133 0 : break;
134 0 : default:
135 0 : return 0;
136 : }
137 :
138 0 : const auto channels = m_format.outputSpec.audioChannelCount;
139 0 : if (channels == 0 || samplesPerChannel == 0) {
140 0 : return 0;
141 : }
142 :
143 0 : constexpr uint32_t BLOCK_FRAMES = 1024;
144 0 : std::vector<FLAC__int32> blockBuffer(static_cast<size_t>(BLOCK_FRAMES) * channels);
145 :
146 0 : for (samples_t frameStart = 0; frameStart < samplesPerChannel;) {
147 0 : const uint32_t framesCount = static_cast<uint32_t>(std::min<samples_t>(BLOCK_FRAMES, samplesPerChannel - frameStart));
148 :
149 0 : for (size_t frame = 0; frame < framesCount; ++frame) {
150 0 : for (audioch_t c = 0; c < channels; ++c) {
151 0 : const size_t i = (static_cast<size_t>(frameStart) + frame) * channels + c;
152 0 : blockBuffer[static_cast<size_t>(frame) * channels + c]
153 0 : = dsp::convertFloatSamples<FLAC__int32>(input[i], bitsPerSample);
154 : }
155 : }
156 :
157 0 : if (!m_flac->process_interleaved(blockBuffer.data(), framesCount)) {
158 0 : return 0;
159 : }
160 :
161 0 : frameStart += framesCount;
162 : }
163 :
164 0 : return static_cast<size_t>(samplesPerChannel) * channels;
165 : }
166 :
167 0 : size_t FlacEncoder::end()
168 : {
169 0 : m_flac->finish();
170 0 : return 0;
171 : }
172 : }
|