LCOV - code coverage report
Current view: top level - muse/framework/audio/engine/internal/export - flacencoder.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 78 0
Test Date: 2026-11-05 04:07:02

            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              : }
        

Generated by: LCOV version 2.0-1