Coverage Report

Created: 2026-11-13 08:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibAudio/MP3Loader.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Arne Elster <arne@elster.li>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include "Loader.h"
10
#include "MP3Types.h"
11
#include <AK/BitStream.h>
12
#include <AK/MemoryStream.h>
13
#include <LibDSP/MDCT.h>
14
15
namespace Audio {
16
17
namespace MP3::Tables {
18
struct ScaleFactorBand;
19
}
20
21
class MP3LoaderPlugin : public LoaderPlugin {
22
public:
23
    explicit MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
24
967
    virtual ~MP3LoaderPlugin() = default;
25
26
    static bool sniff(SeekableStream& stream);
27
    static ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> create(NonnullOwnPtr<SeekableStream>);
28
29
    virtual ErrorOr<Vector<FixedArray<Sample>>, LoaderError> load_chunks(size_t samples_to_read_from_input) override;
30
31
    virtual MaybeLoaderError reset() override;
32
    virtual MaybeLoaderError seek(int const position) override;
33
34
0
    virtual int loaded_samples() override { return m_loaded_samples; }
35
0
    virtual int total_samples() override { return m_total_samples; }
36
0
    virtual u32 sample_rate() override { return m_sample_rate; }
37
0
    virtual u16 num_channels() override { return m_num_channels; }
38
0
    virtual PcmSampleFormat pcm_format() override { return m_sample_format; }
39
0
    virtual ByteString format_name() override { return "MP3 (.mp3)"; }
40
41
private:
42
    MaybeLoaderError initialize();
43
    static MaybeLoaderError skip_id3(SeekableStream& stream);
44
    static MaybeLoaderError synchronize(SeekableStream& stream, size_t sample_index);
45
    static ErrorOr<MP3::Header, LoaderError> read_header(SeekableStream& stream, size_t sample_index);
46
    static ErrorOr<MP3::Header, LoaderError> synchronize_and_read_header(SeekableStream& stream, size_t sample_index);
47
    ErrorOr<MP3::Header, LoaderError> synchronize_and_read_header();
48
    MaybeLoaderError build_seek_table();
49
    ErrorOr<MP3::MP3Frame, LoaderError> read_next_frame();
50
    ErrorOr<MP3::MP3Frame, LoaderError> read_frame_data(MP3::Header const&);
51
    MaybeLoaderError read_side_information(MP3::MP3Frame&);
52
    ErrorOr<size_t, LoaderError> read_scale_factors(MP3::MP3Frame&, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index);
53
    MaybeLoaderError read_huffman_data(MP3::MP3Frame&, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index, size_t granule_bits_read);
54
    static AK::Array<float, 576> calculate_frame_exponents(MP3::MP3Frame const&, size_t granule_index, size_t channel_index);
55
    static void reorder_samples(MP3::Granule&, u32 sample_rate);
56
    static void reduce_alias(MP3::Granule&, size_t max_subband_index = 576);
57
    static void process_stereo(MP3::MP3Frame&, size_t granule_index);
58
    static void transform_samples_to_time(Array<float, 576> const& input, size_t input_offset, Array<float, 36>& output, MP3::BlockType block_type);
59
    static void synthesis(Array<float, 1024>& V, Array<float, 32>& samples, Array<float, 32>& result);
60
    static ReadonlySpan<MP3::Tables::ScaleFactorBand> get_scalefactor_bands(MP3::Granule const&, int samplerate);
61
62
    SeekTable m_seek_table;
63
    AK::Array<AK::Array<AK::Array<float, 18>, 32>, 2> m_last_values {};
64
    AK::Array<AK::Array<float, 1024>, 2> m_synthesis_buffer {};
65
    static DSP::MDCT<36> s_mdct_36;
66
    static DSP::MDCT<12> s_mdct_12;
67
68
    u32 m_sample_rate { 0 };
69
    u8 m_num_channels { 0 };
70
    PcmSampleFormat m_sample_format { PcmSampleFormat::Int16 };
71
    int m_total_samples { 0 };
72
    size_t m_loaded_samples { 0 };
73
74
    AllocatingMemoryStream m_bit_reservoir;
75
};
76
77
}