summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibAudio/MP3Loader.h
blob: 48d5ab1440c20a13364ec4ad2e2838af0d0a1c2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
 * Copyright (c) 2021, Arne Elster <arne@elster.li>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include "Loader.h"
#include "MP3Types.h"
#include <AK/Tuple.h>
#include <LibCore/BitStream.h>
#include <LibCore/MemoryStream.h>
#include <LibCore/Stream.h>
#include <LibDSP/MDCT.h>

namespace Audio {

namespace MP3::Tables {
struct ScaleFactorBand;
}

class MP3LoaderPlugin : public LoaderPlugin {
public:
    explicit MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream);
    virtual ~MP3LoaderPlugin() = default;

    static Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> create(StringView path);
    static Result<NonnullOwnPtr<MP3LoaderPlugin>, LoaderError> create(Bytes buffer);

    virtual LoaderSamples get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB) override;

    virtual MaybeLoaderError reset() override;
    virtual MaybeLoaderError seek(int const position) override;

    virtual int loaded_samples() override { return m_loaded_samples; }
    virtual int total_samples() override { return m_total_samples; }
    virtual u32 sample_rate() override { return m_sample_rate; }
    virtual u16 num_channels() override { return m_num_channels; }
    virtual PcmSampleFormat pcm_format() override { return m_sample_format; }
    virtual DeprecatedString format_name() override { return "MP3 (.mp3)"; }

private:
    MaybeLoaderError initialize();
    MaybeLoaderError synchronize();
    MaybeLoaderError build_seek_table();
    ErrorOr<MP3::Header, LoaderError> read_header();
    ErrorOr<MP3::MP3Frame, LoaderError> read_next_frame();
    ErrorOr<MP3::MP3Frame, LoaderError> read_frame_data(MP3::Header const&);
    MaybeLoaderError read_side_information(MP3::MP3Frame&);
    ErrorOr<size_t, LoaderError> read_scale_factors(MP3::MP3Frame&, Core::Stream::BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index);
    MaybeLoaderError read_huffman_data(MP3::MP3Frame&, Core::Stream::BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index, size_t granule_bits_read);
    static AK::Array<float, 576> calculate_frame_exponents(MP3::MP3Frame const&, size_t granule_index, size_t channel_index);
    static void reorder_samples(MP3::Granule&, u32 sample_rate);
    static void reduce_alias(MP3::Granule&, size_t max_subband_index = 576);
    static void process_stereo(MP3::MP3Frame&, size_t granule_index);
    static void transform_samples_to_time(Array<float, 576> const& input, size_t input_offset, Array<float, 36>& output, MP3::BlockType block_type);
    static void synthesis(Array<float, 1024>& V, Array<float, 32>& samples, Array<float, 32>& result);
    static Span<MP3::Tables::ScaleFactorBand const> get_scalefactor_bands(MP3::Granule const&, int samplerate);

    AK::Vector<AK::Tuple<size_t, int>> m_seek_table;
    AK::Array<AK::Array<AK::Array<float, 18>, 32>, 2> m_last_values {};
    AK::Array<AK::Array<float, 1024>, 2> m_synthesis_buffer {};
    static DSP::MDCT<36> s_mdct_36;
    static DSP::MDCT<12> s_mdct_12;

    u32 m_sample_rate { 0 };
    u8 m_num_channels { 0 };
    PcmSampleFormat m_sample_format { PcmSampleFormat::Int16 };
    int m_total_samples { 0 };
    size_t m_loaded_samples { 0 };

    AK::Optional<MP3::MP3Frame> m_current_frame;
    u32 m_current_frame_read;
    OwnPtr<Core::Stream::BigEndianInputBitStream> m_bitstream;
    Core::Stream::AllocatingMemoryStream m_bit_reservoir;
};

}