/src/serenity/Userland/Libraries/LibAudio/MP3Loader.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, Arne Elster <arne@elster.li> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include "MP3Loader.h" |
8 | | #include "MP3HuffmanTables.h" |
9 | | #include "MP3Tables.h" |
10 | | #include "MP3Types.h" |
11 | | #include <AK/Endian.h> |
12 | | #include <AK/FixedArray.h> |
13 | | #include <LibCore/File.h> |
14 | | |
15 | | namespace Audio { |
16 | | |
17 | | DSP::MDCT<12> MP3LoaderPlugin::s_mdct_12; |
18 | | DSP::MDCT<36> MP3LoaderPlugin::s_mdct_36; |
19 | | |
20 | | MP3LoaderPlugin::MP3LoaderPlugin(NonnullOwnPtr<SeekableStream> stream) |
21 | 956 | : LoaderPlugin(move(stream)) |
22 | 956 | { |
23 | 956 | } |
24 | | |
25 | | MaybeLoaderError MP3LoaderPlugin::skip_id3(SeekableStream& stream) |
26 | 956 | { |
27 | | // FIXME: This is a bit of a hack until we have a proper ID3 reader and MP3 demuxer. |
28 | | // Based on https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.2.html |
29 | 956 | char identifier_buffer[3] = { 0, 0, 0 }; |
30 | 956 | auto read_identifier = StringView(TRY(stream.read_some({ &identifier_buffer[0], sizeof(identifier_buffer) }))); |
31 | 956 | if (read_identifier == "ID3"sv) { |
32 | 0 | [[maybe_unused]] auto version = TRY(stream.read_value<u8>()); |
33 | 0 | [[maybe_unused]] auto revision = TRY(stream.read_value<u8>()); |
34 | 0 | [[maybe_unused]] auto flags = TRY(stream.read_value<u8>()); |
35 | 0 | auto size = 0; |
36 | 0 | for (auto i = 0; i < 4; i++) { |
37 | | // Each byte has a zeroed most significant bit to prevent it from looking like a sync code. |
38 | 0 | auto byte = TRY(stream.read_value<u8>()); |
39 | 0 | size <<= 7; |
40 | 0 | size |= byte & 0x7F; |
41 | 0 | } |
42 | 0 | TRY(stream.seek(size, SeekMode::FromCurrentPosition)); |
43 | 956 | } else if (read_identifier != "TAG"sv) { |
44 | 917 | MUST(stream.seek(-static_cast<int>(read_identifier.length()), SeekMode::FromCurrentPosition)); |
45 | 917 | } |
46 | 956 | return {}; |
47 | 956 | } |
48 | | |
49 | | bool MP3LoaderPlugin::sniff(SeekableStream& stream) |
50 | 0 | { |
51 | 0 | auto skip_id3_result = skip_id3(stream); |
52 | 0 | if (skip_id3_result.is_error()) |
53 | 0 | return false; |
54 | 0 | return !synchronize_and_read_header(stream, 0).is_error(); |
55 | 0 | } |
56 | | |
57 | | ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> MP3LoaderPlugin::create(NonnullOwnPtr<SeekableStream> stream) |
58 | 956 | { |
59 | 956 | auto loader = make<MP3LoaderPlugin>(move(stream)); |
60 | 956 | TRY(loader->initialize()); |
61 | 842 | return loader; |
62 | 956 | } |
63 | | |
64 | | MaybeLoaderError MP3LoaderPlugin::initialize() |
65 | 956 | { |
66 | 956 | TRY(build_seek_table()); |
67 | | |
68 | 867 | TRY(seek(0)); |
69 | 867 | auto header = TRY(synchronize_and_read_header()); |
70 | | |
71 | 842 | m_sample_rate = header.samplerate; |
72 | 842 | m_num_channels = header.channel_count(); |
73 | 842 | m_loaded_samples = 0; |
74 | | |
75 | 842 | TRY(seek(0)); |
76 | | |
77 | 842 | return {}; |
78 | 842 | } |
79 | | |
80 | | MaybeLoaderError MP3LoaderPlugin::reset() |
81 | 0 | { |
82 | 0 | TRY(seek(0)); |
83 | 0 | m_synthesis_buffer = {}; |
84 | 0 | m_loaded_samples = 0; |
85 | 0 | TRY(m_bit_reservoir.discard(m_bit_reservoir.used_buffer_size())); |
86 | 0 | return {}; |
87 | 0 | } |
88 | | |
89 | | MaybeLoaderError MP3LoaderPlugin::seek(int const position) |
90 | 1.70k | { |
91 | 1.70k | auto seek_entry = m_seek_table.seek_point_before(position); |
92 | 1.70k | if (seek_entry.has_value()) { |
93 | 1.68k | TRY(m_stream->seek(seek_entry->byte_offset, SeekMode::SetPosition)); |
94 | 1.68k | m_loaded_samples = seek_entry->sample_index; |
95 | 1.68k | } |
96 | 1.70k | m_synthesis_buffer = {}; |
97 | 1.70k | TRY(m_bit_reservoir.discard(m_bit_reservoir.used_buffer_size())); |
98 | 1.70k | return {}; |
99 | 1.70k | } |
100 | | |
101 | | ErrorOr<Vector<FixedArray<Sample>>, LoaderError> MP3LoaderPlugin::load_chunks(size_t samples_to_read_from_input) |
102 | 8.09k | { |
103 | 8.09k | int samples_to_read = samples_to_read_from_input; |
104 | 8.09k | Vector<FixedArray<Sample>> frames; |
105 | 37.9k | while (samples_to_read > 0) { |
106 | 30.6k | FixedArray<Sample> samples = TRY(FixedArray<Sample>::create(MP3::frame_size)); |
107 | | |
108 | 30.6k | auto maybe_frame = read_next_frame(); |
109 | 30.6k | if (maybe_frame.is_error()) { |
110 | 842 | if (m_stream->is_eof()) |
111 | 674 | return Vector<FixedArray<Sample>> {}; |
112 | 168 | return maybe_frame.release_error(); |
113 | 842 | } |
114 | 29.8k | auto frame = maybe_frame.release_value(); |
115 | | |
116 | 29.8k | bool const is_stereo = frame.header.channel_count() == 2; |
117 | 29.8k | size_t current_frame_read = 0; |
118 | 17.2M | for (; current_frame_read < MP3::granule_size; current_frame_read++) { |
119 | 17.1M | auto const left_sample = frame.channels[0].granules[0].pcm[current_frame_read / 32][current_frame_read % 32]; |
120 | 17.1M | auto const right_sample = is_stereo ? frame.channels[1].granules[0].pcm[current_frame_read / 32][current_frame_read % 32] : left_sample; |
121 | 17.1M | samples[current_frame_read] = Sample { left_sample, right_sample }; |
122 | 17.1M | samples_to_read--; |
123 | 17.1M | } |
124 | 17.2M | for (; current_frame_read < MP3::frame_size; current_frame_read++) { |
125 | 17.1M | auto const left_sample = frame.channels[0].granules[1].pcm[(current_frame_read - MP3::granule_size) / 32][(current_frame_read - MP3::granule_size) % 32]; |
126 | 17.1M | auto const right_sample = is_stereo ? frame.channels[1].granules[1].pcm[(current_frame_read - MP3::granule_size) / 32][(current_frame_read - MP3::granule_size) % 32] : left_sample; |
127 | 17.1M | samples[current_frame_read] = Sample { left_sample, right_sample }; |
128 | 17.1M | samples_to_read--; |
129 | 17.1M | } |
130 | 29.8k | m_loaded_samples += samples.size(); |
131 | 29.8k | TRY(frames.try_append(move(samples))); |
132 | 29.8k | } |
133 | | |
134 | 7.24k | return frames; |
135 | 8.09k | } |
136 | | |
137 | | MaybeLoaderError MP3LoaderPlugin::build_seek_table() |
138 | 956 | { |
139 | 956 | VERIFY(MUST(m_stream->tell()) == 0); |
140 | 1.91k | TRY(skip_id3(*m_stream)); |
141 | | |
142 | 1.91k | int sample_count = 0; |
143 | 1.91k | size_t frame_count = 0; |
144 | 1.91k | m_seek_table = {}; |
145 | | |
146 | 257k | while (true) { |
147 | 257k | auto error_or_header = synchronize_and_read_header(); |
148 | 257k | if (error_or_header.is_error()) |
149 | 867 | break; |
150 | | |
151 | 256k | if (frame_count % 10 == 0) { |
152 | 26.3k | auto frame_pos = TRY(m_stream->tell()) - error_or_header.value().header_size; |
153 | 26.3k | TRY(m_seek_table.insert_seek_point({ static_cast<u64>(sample_count), frame_pos })); |
154 | 26.3k | } |
155 | | |
156 | 256k | frame_count++; |
157 | 256k | sample_count += MP3::frame_size; |
158 | | |
159 | 256k | TRY(m_stream->seek(error_or_header.value().frame_size - error_or_header.value().header_size, SeekMode::FromCurrentPosition)); |
160 | 256k | } |
161 | 867 | m_total_samples = sample_count; |
162 | 867 | return {}; |
163 | 1.91k | } |
164 | | |
165 | | ErrorOr<MP3::Header, LoaderError> MP3LoaderPlugin::read_header(SeekableStream& stream, size_t sample_index) |
166 | 1.40M | { |
167 | 1.40M | auto bitstream = BigEndianInputBitStream(MaybeOwned<Stream>(stream)); |
168 | 2.80M | if (TRY(bitstream.read_bits(4)) != 0xF) |
169 | 0 | return LoaderError { LoaderError::Category::Format, sample_index, "Frame header did not start with sync code."_fly_string }; |
170 | 1.40M | MP3::Header header; |
171 | 1.40M | header.id = TRY(bitstream.read_bit()); |
172 | 1.40M | header.layer = MP3::Tables::LayerNumberLookup[TRY(bitstream.read_bits(2))]; |
173 | 1.40M | if (header.layer <= 0) |
174 | 461 | return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid layer number."_fly_string }; |
175 | 1.40M | header.protection_bit = TRY(bitstream.read_bit()); |
176 | 1.40M | header.bitrate = MP3::Tables::BitratesPerLayerLookup[header.layer - 1][TRY(bitstream.read_bits(4))]; |
177 | 1.40M | if (header.bitrate <= 0) |
178 | 295k | return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid bitrate."_fly_string }; |
179 | 1.10M | header.samplerate = MP3::Tables::SampleratesLookup[TRY(bitstream.read_bits(2))]; |
180 | 1.10M | if (header.samplerate <= 0) |
181 | 792k | return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid samplerate."_fly_string }; |
182 | 313k | header.padding_bit = TRY(bitstream.read_bit()); |
183 | 313k | header.private_bit = TRY(bitstream.read_bit()); |
184 | 313k | header.mode = static_cast<MP3::Mode>(TRY(bitstream.read_bits(2))); |
185 | 313k | header.mode_extension = static_cast<MP3::ModeExtension>(TRY(bitstream.read_bits(2))); |
186 | 313k | header.copyright_bit = TRY(bitstream.read_bit()); |
187 | 313k | header.original_bit = TRY(bitstream.read_bit()); |
188 | 313k | header.emphasis = static_cast<MP3::Emphasis>(TRY(bitstream.read_bits(2))); |
189 | 313k | header.header_size = 4; |
190 | 313k | if (!header.protection_bit) { |
191 | 86.2k | header.crc16 = TRY(bitstream.read_bits<u16>(16)); |
192 | 86.2k | header.header_size += 2; |
193 | 86.2k | } |
194 | 313k | header.frame_size = 144 * header.bitrate * 1000 / header.samplerate + header.padding_bit; |
195 | 313k | header.slot_count = header.frame_size - ((header.channel_count() == 2 ? 32 : 17) + header.header_size); |
196 | 313k | return header; |
197 | 313k | } |
198 | | |
199 | | ErrorOr<MP3::Header, LoaderError> MP3LoaderPlugin::synchronize_and_read_header(SeekableStream& stream, size_t sample_index) |
200 | 289k | { |
201 | 1.40M | while (!stream.is_eof()) { |
202 | 1.40M | bool last_was_all_set = false; |
203 | | |
204 | 18.1M | while (!stream.is_eof()) { |
205 | 18.1M | u8 byte = TRY(stream.read_value<u8>()); |
206 | 18.1M | if (last_was_all_set && (byte & 0xF0) == 0xF0) { |
207 | | // Seek back, since there is still data we have not consumed within the current byte. |
208 | | // read_header() will consume and check these 4 bits itself and then continue reading |
209 | | // the rest of the data from there. |
210 | 1.40M | TRY(stream.seek(-1, SeekMode::FromCurrentPosition)); |
211 | 1.40M | break; |
212 | 1.40M | } |
213 | 16.7M | last_was_all_set = byte == 0xFF; |
214 | 16.7M | } |
215 | | |
216 | 1.40M | auto header_start = TRY(stream.tell()); |
217 | 1.40M | auto header_result = read_header(stream, sample_index); |
218 | 1.40M | if (header_result.is_error() || header_result.value().id != 1 || header_result.value().layer != 3) { |
219 | 1.11M | TRY(stream.seek(header_start, SeekMode::SetPosition)); |
220 | 1.11M | continue; |
221 | 1.11M | } |
222 | 287k | return header_result.value(); |
223 | 1.40M | } |
224 | 1.30k | return LoaderError { LoaderError::Category::Format, sample_index, "Failed to synchronize."_fly_string }; |
225 | 289k | } |
226 | | |
227 | | ErrorOr<MP3::Header, LoaderError> MP3LoaderPlugin::synchronize_and_read_header() |
228 | 289k | { |
229 | 289k | return MP3LoaderPlugin::synchronize_and_read_header(*m_stream, m_loaded_samples); |
230 | 289k | } |
231 | | |
232 | | ErrorOr<MP3::MP3Frame, LoaderError> MP3LoaderPlugin::read_next_frame() |
233 | 30.6k | { |
234 | 30.6k | return read_frame_data(TRY(synchronize_and_read_header())); |
235 | 30.6k | } |
236 | | |
237 | | ErrorOr<MP3::MP3Frame, LoaderError> MP3LoaderPlugin::read_frame_data(MP3::Header const& header) |
238 | 30.2k | { |
239 | 30.2k | MP3::MP3Frame frame { header }; |
240 | | |
241 | 30.2k | TRY(read_side_information(frame)); |
242 | | |
243 | 30.2k | auto maybe_buffer = ByteBuffer::create_uninitialized(header.slot_count); |
244 | 30.2k | if (maybe_buffer.is_error()) |
245 | 0 | return LoaderError { LoaderError::Category::IO, m_loaded_samples, "Out of memory"_fly_string }; |
246 | 30.2k | auto& buffer = maybe_buffer.value(); |
247 | | |
248 | 30.2k | size_t old_reservoir_size = m_bit_reservoir.used_buffer_size(); |
249 | 30.2k | TRY(m_stream->read_until_filled(buffer)); |
250 | 30.2k | TRY(m_bit_reservoir.write_until_depleted(buffer)); |
251 | | |
252 | | // If we don't have enough data in the reservoir to process this frame, skip it (but keep the data). |
253 | 30.2k | if (old_reservoir_size < static_cast<size_t>(frame.main_data_begin)) |
254 | 1.63k | return frame; |
255 | | |
256 | 57.2k | TRY(m_bit_reservoir.discard(old_reservoir_size - frame.main_data_begin)); |
257 | | |
258 | 57.2k | BigEndianInputBitStream reservoir_stream { MaybeOwned<Stream>(m_bit_reservoir) }; |
259 | | |
260 | 85.3k | for (size_t granule_index = 0; granule_index < 2; granule_index++) { |
261 | 169k | for (size_t channel_index = 0; channel_index < header.channel_count(); channel_index++) { |
262 | 112k | size_t scale_factor_size = TRY(read_scale_factors(frame, reservoir_stream, granule_index, channel_index)); |
263 | 112k | TRY(read_huffman_data(frame, reservoir_stream, granule_index, channel_index, scale_factor_size)); |
264 | 112k | if (frame.channels[channel_index].granules[granule_index].block_type == MP3::BlockType::Short) { |
265 | 11.2k | reorder_samples(frame.channels[channel_index].granules[granule_index], frame.header.samplerate); |
266 | | |
267 | | // Only reduce alias for lowest 2 bands as they're long. |
268 | | // Afaik this is not mentioned in the ISO spec, but it is addressed in the |
269 | | // changelog for the ISO compliance tests. |
270 | 11.2k | if (frame.channels[channel_index].granules[granule_index].mixed_block_flag) |
271 | 6.42k | reduce_alias(frame.channels[channel_index].granules[granule_index], 36); |
272 | 100k | } else { |
273 | 100k | reduce_alias(frame.channels[channel_index].granules[granule_index]); |
274 | 100k | } |
275 | 112k | } |
276 | | |
277 | 57.1k | if (header.mode == MP3::Mode::JointStereo) { |
278 | 31.9k | process_stereo(frame, granule_index); |
279 | 31.9k | } |
280 | 56.6k | } |
281 | | |
282 | 84.6k | for (size_t granule_index = 0; granule_index < 2; granule_index++) { |
283 | 167k | for (size_t channel_index = 0; channel_index < header.channel_count(); channel_index++) { |
284 | 111k | auto& granule = frame.channels[channel_index].granules[granule_index]; |
285 | | |
286 | 3.67M | for (size_t i = 0; i < MP3::granule_size; i += 18) { |
287 | 3.56M | MP3::BlockType block_type = granule.block_type; |
288 | 3.56M | if (i < 36 && granule.mixed_block_flag) { |
289 | | // ISO/IEC 11172-3: if mixed_block_flag is set, the lowest two subbands are transformed with normal window. |
290 | 19.6k | block_type = MP3::BlockType::Normal; |
291 | 19.6k | } |
292 | | |
293 | 3.56M | Array<float, 36> output; |
294 | 3.56M | transform_samples_to_time(granule.samples, i, output, block_type); |
295 | | |
296 | 3.56M | int const subband_index = i / 18; |
297 | 67.7M | for (size_t sample_index = 0; sample_index < 18; sample_index++) { |
298 | | // overlap add |
299 | 64.1M | granule.filter_bank_input[subband_index][sample_index] = output[sample_index] + m_last_values[channel_index][subband_index][sample_index]; |
300 | 64.1M | m_last_values[channel_index][subband_index][sample_index] = output[sample_index + 18]; |
301 | | |
302 | | // frequency inversion |
303 | 64.1M | if (subband_index % 2 == 1 && sample_index % 2 == 1) |
304 | 16.0M | granule.filter_bank_input[subband_index][sample_index] *= -1; |
305 | 64.1M | } |
306 | 3.56M | } |
307 | 111k | } |
308 | 56.4k | } |
309 | | |
310 | 28.2k | Array<float, 32> in_samples; |
311 | 83.9k | for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { |
312 | 167k | for (size_t granule_index = 0; granule_index < 2; granule_index++) { |
313 | 111k | auto& granule = frame.channels[channel_index].granules[granule_index]; |
314 | 2.11M | for (size_t sample_index = 0; sample_index < 18; sample_index++) { |
315 | 66.1M | for (size_t band_index = 0; band_index < 32; band_index++) { |
316 | 64.1M | in_samples[band_index] = granule.filter_bank_input[band_index][sample_index]; |
317 | 64.1M | } |
318 | 2.00M | synthesis(m_synthesis_buffer[channel_index], in_samples, granule.pcm[sample_index]); |
319 | 2.00M | } |
320 | 111k | } |
321 | 55.7k | } |
322 | | |
323 | 28.2k | return frame; |
324 | 57.2k | } |
325 | | |
326 | | MaybeLoaderError MP3LoaderPlugin::read_side_information(MP3::MP3Frame& frame) |
327 | 30.2k | { |
328 | 30.2k | auto bitstream = BigEndianInputBitStream(MaybeOwned<Stream>(*m_stream)); |
329 | | |
330 | 30.2k | frame.main_data_begin = TRY(bitstream.read_bits(9)); |
331 | | |
332 | 30.2k | if (frame.header.channel_count() == 1) { |
333 | 1.32k | frame.private_bits = TRY(bitstream.read_bits(5)); |
334 | 28.9k | } else { |
335 | 28.9k | frame.private_bits = TRY(bitstream.read_bits(3)); |
336 | 28.9k | } |
337 | | |
338 | 89.5k | for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { |
339 | 296k | for (size_t scale_factor_selection_info_band = 0; scale_factor_selection_info_band < 4; scale_factor_selection_info_band++) { |
340 | 236k | frame.channels[channel_index].scale_factor_selection_info[scale_factor_selection_info_band] = TRY(bitstream.read_bit()); |
341 | 236k | } |
342 | 59.2k | } |
343 | | |
344 | 90.8k | for (size_t granule_index = 0; granule_index < 2; granule_index++) { |
345 | 179k | for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { |
346 | 118k | auto& granule = frame.channels[channel_index].granules[granule_index]; |
347 | 118k | granule.part_2_3_length = TRY(bitstream.read_bits(12)); |
348 | 118k | granule.big_values = TRY(bitstream.read_bits(9)); |
349 | 118k | granule.global_gain = TRY(bitstream.read_bits(8)); |
350 | 118k | granule.scalefac_compress = TRY(bitstream.read_bits(4)); |
351 | 118k | granule.window_switching_flag = TRY(bitstream.read_bit()); |
352 | 118k | if (granule.window_switching_flag) { |
353 | 22.1k | granule.block_type = static_cast<MP3::BlockType>(TRY(bitstream.read_bits(2))); |
354 | 22.1k | granule.mixed_block_flag = TRY(bitstream.read_bit()); |
355 | 66.3k | for (size_t region = 0; region < 2; region++) |
356 | 44.2k | granule.table_select[region] = TRY(bitstream.read_bits(5)); |
357 | 88.5k | for (size_t window = 0; window < 3; window++) |
358 | 66.3k | granule.sub_block_gain[window] = TRY(bitstream.read_bits(3)); |
359 | 22.1k | granule.region0_count = (granule.block_type == MP3::BlockType::Short && !granule.mixed_block_flag) ? 8 : 7; |
360 | 22.1k | granule.region1_count = 36; |
361 | 96.3k | } else { |
362 | 385k | for (size_t region = 0; region < 3; region++) |
363 | 289k | granule.table_select[region] = TRY(bitstream.read_bits(5)); |
364 | 96.3k | granule.region0_count = TRY(bitstream.read_bits(4)); |
365 | 96.3k | granule.region1_count = TRY(bitstream.read_bits(3)); |
366 | 96.3k | } |
367 | 118k | granule.preflag = TRY(bitstream.read_bit()); |
368 | 118k | granule.scalefac_scale = TRY(bitstream.read_bit()); |
369 | 118k | granule.count1table_select = TRY(bitstream.read_bit()); |
370 | 118k | } |
371 | 60.5k | } |
372 | 30.2k | return {}; |
373 | 30.2k | } |
374 | | |
375 | | // From ISO/IEC 11172-3 (2.4.3.4.7.1) |
376 | | Array<float, MP3::granule_size> MP3LoaderPlugin::calculate_frame_exponents(MP3::MP3Frame const& frame, size_t granule_index, size_t channel_index) |
377 | 112k | { |
378 | 112k | Array<float, MP3::granule_size> exponents; |
379 | | |
380 | 2.65M | auto fill_band = [&exponents](float exponent, size_t start, size_t end) { |
381 | 67.4M | for (size_t j = start; j <= end; j++) { |
382 | 64.7M | exponents[j] = exponent; |
383 | 64.7M | } |
384 | 2.65M | }; |
385 | | |
386 | 112k | auto const& channel = frame.channels[channel_index]; |
387 | 112k | auto const& granule = frame.channels[channel_index].granules[granule_index]; |
388 | | |
389 | 112k | auto const scale_factor_bands = get_scalefactor_bands(granule, frame.header.samplerate); |
390 | 112k | float const scale_factor_multiplier = granule.scalefac_scale ? 1 : 0.5; |
391 | 112k | int const gain = granule.global_gain - 210; |
392 | | |
393 | 112k | if (granule.block_type != MP3::BlockType::Short) { |
394 | 2.32M | for (size_t band_index = 0; band_index < 22; band_index++) { |
395 | 2.22M | float const exponent = gain / 4.0f - (scale_factor_multiplier * (channel.scale_factors[band_index] + granule.preflag * MP3::Tables::Pretab[band_index])); |
396 | 2.22M | fill_band(AK::pow<float>(2.0, exponent), scale_factor_bands[band_index].start, scale_factor_bands[band_index].end); |
397 | 2.22M | } |
398 | 101k | } else { |
399 | 11.2k | size_t band_index = 0; |
400 | 11.2k | size_t sample_count = 0; |
401 | | |
402 | 11.2k | if (granule.mixed_block_flag) { |
403 | 58.2k | while (sample_count < 36) { |
404 | 51.7k | float const exponent = gain / 4.0f - (scale_factor_multiplier * (channel.scale_factors[band_index] + granule.preflag * MP3::Tables::Pretab[band_index])); |
405 | 51.7k | fill_band(AK::pow<float>(2.0, exponent), scale_factor_bands[band_index].start, scale_factor_bands[band_index].end); |
406 | 51.7k | sample_count += scale_factor_bands[band_index].width; |
407 | 51.7k | band_index++; |
408 | 51.7k | } |
409 | 6.47k | } |
410 | | |
411 | 11.2k | float const gain0 = (gain - 8 * granule.sub_block_gain[0]) / 4.0; |
412 | 11.2k | float const gain1 = (gain - 8 * granule.sub_block_gain[1]) / 4.0; |
413 | 11.2k | float const gain2 = (gain - 8 * granule.sub_block_gain[2]) / 4.0; |
414 | | |
415 | 138k | while (sample_count < MP3::granule_size && band_index < scale_factor_bands.size()) { |
416 | 127k | float const exponent0 = gain0 - (scale_factor_multiplier * channel.scale_factors[band_index + 0]); |
417 | 127k | float const exponent1 = gain1 - (scale_factor_multiplier * channel.scale_factors[band_index + 1]); |
418 | 127k | float const exponent2 = gain2 - (scale_factor_multiplier * channel.scale_factors[band_index + 2]); |
419 | | |
420 | 127k | fill_band(AK::pow<float>(2.0, exponent0), scale_factor_bands[band_index + 0].start, scale_factor_bands[band_index + 0].end); |
421 | 127k | sample_count += scale_factor_bands[band_index + 0].width; |
422 | 127k | fill_band(AK::pow<float>(2.0, exponent1), scale_factor_bands[band_index + 1].start, scale_factor_bands[band_index + 1].end); |
423 | 127k | sample_count += scale_factor_bands[band_index + 1].width; |
424 | 127k | fill_band(AK::pow<float>(2.0, exponent2), scale_factor_bands[band_index + 2].start, scale_factor_bands[band_index + 2].end); |
425 | 127k | sample_count += scale_factor_bands[band_index + 2].width; |
426 | | |
427 | 127k | band_index += 3; |
428 | 127k | } |
429 | | |
430 | 11.2k | while (sample_count < MP3::granule_size) |
431 | 0 | exponents[sample_count++] = 0; |
432 | 11.2k | } |
433 | 112k | return exponents; |
434 | 112k | } |
435 | | |
436 | | ErrorOr<size_t, LoaderError> MP3LoaderPlugin::read_scale_factors(MP3::MP3Frame& frame, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index) |
437 | 112k | { |
438 | 112k | auto& channel = frame.channels[channel_index]; |
439 | 112k | auto const& granule = channel.granules[granule_index]; |
440 | 112k | size_t band_index = 0; |
441 | 112k | size_t bits_read = 0; |
442 | | |
443 | 112k | if (granule.window_switching_flag && granule.block_type == MP3::BlockType::Short) { |
444 | 11.2k | if (granule.mixed_block_flag) { |
445 | 58.3k | for (size_t i = 0; i < 8; i++) { |
446 | 51.8k | auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; |
447 | 51.8k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
448 | 51.8k | bits_read += bits; |
449 | 51.8k | } |
450 | 64.7k | for (size_t i = 3; i < 12; i++) { |
451 | 58.2k | auto const bits = i <= 5 ? MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress] : MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; |
452 | 58.2k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
453 | 58.2k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
454 | 58.2k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
455 | 58.2k | bits_read += 3 * bits; |
456 | 58.2k | } |
457 | 6.47k | } else { |
458 | 62.5k | for (size_t i = 0; i < 12; i++) { |
459 | 57.7k | auto const bits = i <= 5 ? MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress] : MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; |
460 | 57.7k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
461 | 57.7k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
462 | 57.7k | channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); |
463 | 57.7k | bits_read += 3 * bits; |
464 | 57.7k | } |
465 | 4.81k | } |
466 | 11.2k | channel.scale_factors[band_index++] = 0; |
467 | 11.2k | channel.scale_factors[band_index++] = 0; |
468 | 11.2k | channel.scale_factors[band_index++] = 0; |
469 | 101k | } else { |
470 | 101k | if ((channel.scale_factor_selection_info[0] == 0) || (granule_index == 0)) { |
471 | 679k | for (band_index = 0; band_index < 6; band_index++) { |
472 | 582k | auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; |
473 | 582k | channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); |
474 | 582k | bits_read += bits; |
475 | 582k | } |
476 | 97.0k | } |
477 | 101k | if ((channel.scale_factor_selection_info[1] == 0) || (granule_index == 0)) { |
478 | 581k | for (band_index = 6; band_index < 11; band_index++) { |
479 | 484k | auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; |
480 | 484k | channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); |
481 | 484k | bits_read += bits; |
482 | 484k | } |
483 | 96.8k | } |
484 | 101k | if ((channel.scale_factor_selection_info[2] == 0) || (granule_index == 0)) { |
485 | 569k | for (band_index = 11; band_index < 16; band_index++) { |
486 | 474k | auto const bits = MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; |
487 | 474k | channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); |
488 | 474k | bits_read += bits; |
489 | 474k | } |
490 | 94.9k | } |
491 | 101k | if ((channel.scale_factor_selection_info[3] == 0) || (granule_index == 0)) { |
492 | 549k | for (band_index = 16; band_index < 21; band_index++) { |
493 | 457k | auto const bits = MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; |
494 | 457k | channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); |
495 | 457k | bits_read += bits; |
496 | 457k | } |
497 | 91.5k | } |
498 | 101k | channel.scale_factors[21] = 0; |
499 | 101k | } |
500 | | |
501 | 112k | return bits_read; |
502 | 112k | } |
503 | | |
504 | | MaybeLoaderError MP3LoaderPlugin::read_huffman_data(MP3::MP3Frame& frame, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index, size_t granule_bits_read) |
505 | 112k | { |
506 | 112k | auto const exponents = calculate_frame_exponents(frame, granule_index, channel_index); |
507 | 112k | auto& granule = frame.channels[channel_index].granules[granule_index]; |
508 | | |
509 | 112k | auto const scale_factor_bands = get_scalefactor_bands(granule, frame.header.samplerate); |
510 | 112k | size_t const scale_factor_band_index1 = granule.region0_count + 1; |
511 | 112k | size_t const scale_factor_band_index2 = min(scale_factor_bands.size() - 1, scale_factor_band_index1 + granule.region1_count + 1); |
512 | | |
513 | 112k | bool const is_short_granule = granule.window_switching_flag && granule.block_type == MP3::BlockType::Short; |
514 | 112k | size_t const region1_start = is_short_granule ? 36 : scale_factor_bands[scale_factor_band_index1].start; |
515 | 112k | size_t const region2_start = is_short_granule ? MP3::granule_size : scale_factor_bands[scale_factor_band_index2].start; |
516 | | |
517 | 14.4M | auto requantize = [](int const sample, float const exponent) -> float { |
518 | 14.4M | int const sign = sample < 0 ? -1 : 1; |
519 | 14.4M | int const magnitude = AK::abs(sample); |
520 | 14.4M | return sign * AK::pow<float>(static_cast<float>(magnitude), 4 / 3.0) * exponent; |
521 | 14.4M | }; |
522 | | |
523 | 112k | size_t count = 0; |
524 | | |
525 | | // 2.4.3.4.6: "Decoding is done until all Huffman code bits have been decoded |
526 | | // or until quantized values representing 576 frequency lines have been decoded, |
527 | | // whichever comes first." |
528 | 112k | auto max_count = min(granule.big_values * 2, MP3::granule_size); |
529 | | |
530 | 5.96M | for (; count < max_count; count += 2) { |
531 | 5.84M | MP3::Tables::Huffman::HuffmanTreeXY const* tree = nullptr; |
532 | | |
533 | 5.84M | if (count < region1_start) { |
534 | 416k | tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[0]]; |
535 | 5.43M | } else if (count < region2_start) { |
536 | 1.97M | tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[1]]; |
537 | 3.45M | } else { |
538 | 3.45M | tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[2]]; |
539 | 3.45M | } |
540 | | |
541 | 5.84M | if (!tree || tree->nodes.is_empty()) { |
542 | 11 | return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame references invalid huffman table."_fly_string }; |
543 | 11 | } |
544 | | |
545 | | // Assumption: There's enough bits to read. 32 is just a placeholder for "unlimited". |
546 | | // There are no 32 bit long huffman codes in the tables. |
547 | 5.84M | auto const entry = MP3::Tables::Huffman::huffman_decode(reservoir, tree->nodes, 32); |
548 | 5.84M | granule_bits_read += entry.bits_read; |
549 | 5.84M | if (!entry.code.has_value()) |
550 | 88 | return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame contains invalid huffman data."_fly_string }; |
551 | 5.84M | int x = entry.code->symbol.x; |
552 | 5.84M | int y = entry.code->symbol.y; |
553 | | |
554 | 5.84M | if (x == 15 && tree->linbits > 0) { |
555 | 35.6k | x += TRY(reservoir.read_bits(tree->linbits)); |
556 | 35.6k | granule_bits_read += tree->linbits; |
557 | 35.6k | } |
558 | 5.84M | if (x != 0) { |
559 | 451k | if (TRY(reservoir.read_bit())) |
560 | 94.8k | x = -x; |
561 | 451k | granule_bits_read++; |
562 | 451k | } |
563 | | |
564 | 5.84M | if (y == 15 && tree->linbits > 0) { |
565 | 74.2k | y += TRY(reservoir.read_bits(tree->linbits)); |
566 | 74.1k | granule_bits_read += tree->linbits; |
567 | 74.1k | } |
568 | 5.84M | if (y != 0) { |
569 | 449k | if (TRY(reservoir.read_bit())) |
570 | 113k | y = -y; |
571 | 449k | granule_bits_read++; |
572 | 449k | } |
573 | | |
574 | 5.84M | granule.samples[count + 0] = requantize(x, exponents[count + 0]); |
575 | 5.84M | granule.samples[count + 1] = requantize(y, exponents[count + 1]); |
576 | 5.84M | } |
577 | | |
578 | 112k | ReadonlySpan<MP3::Tables::Huffman::HuffmanNode<MP3::Tables::Huffman::HuffmanVWXY>> count1table = granule.count1table_select ? MP3::Tables::Huffman::TreeB : MP3::Tables::Huffman::TreeA; |
579 | | |
580 | | // count1 is not known. We have to read huffman encoded values |
581 | | // until we've exhausted the granule's bits. We know the size of |
582 | | // the granule from part2_3_length, which is the number of bits |
583 | | // used for scalefactors and huffman data (in the granule). |
584 | 789k | while (granule_bits_read < granule.part_2_3_length && count <= MP3::granule_size - 4) { |
585 | 683k | auto const entry = MP3::Tables::Huffman::huffman_decode(reservoir, count1table, granule.part_2_3_length - granule_bits_read); |
586 | 683k | granule_bits_read += entry.bits_read; |
587 | 683k | if (!entry.code.has_value()) |
588 | 67 | return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame contains invalid huffman data."_fly_string }; |
589 | 683k | int v = entry.code->symbol.v; |
590 | 683k | if (v != 0) { |
591 | 254k | if (granule_bits_read >= granule.part_2_3_length) |
592 | 1.27k | break; |
593 | 253k | if (TRY(reservoir.read_bit())) |
594 | 37.8k | v = -v; |
595 | 253k | granule_bits_read++; |
596 | 253k | } |
597 | 682k | int w = entry.code->symbol.w; |
598 | 682k | if (w != 0) { |
599 | 83.0k | if (granule_bits_read >= granule.part_2_3_length) |
600 | 659 | break; |
601 | 82.3k | if (TRY(reservoir.read_bit())) |
602 | 50.1k | w = -w; |
603 | 82.3k | granule_bits_read++; |
604 | 82.3k | } |
605 | 681k | int x = entry.code->symbol.x; |
606 | 681k | if (x != 0) { |
607 | 247k | if (granule_bits_read >= granule.part_2_3_length) |
608 | 3.90k | break; |
609 | 243k | if (TRY(reservoir.read_bit())) |
610 | 24.0k | x = -x; |
611 | 243k | granule_bits_read++; |
612 | 243k | } |
613 | 678k | int y = entry.code->symbol.y; |
614 | 678k | if (y != 0) { |
615 | 273k | if (granule_bits_read >= granule.part_2_3_length) |
616 | 1.15k | break; |
617 | 272k | if (TRY(reservoir.read_bit())) |
618 | 58.7k | y = -y; |
619 | 272k | granule_bits_read++; |
620 | 272k | } |
621 | | |
622 | 676k | granule.samples[count + 0] = requantize(v, exponents[count + 0]); |
623 | 676k | granule.samples[count + 1] = requantize(w, exponents[count + 1]); |
624 | 676k | granule.samples[count + 2] = requantize(x, exponents[count + 2]); |
625 | 676k | granule.samples[count + 3] = requantize(y, exponents[count + 3]); |
626 | | |
627 | 676k | count += 4; |
628 | 676k | } |
629 | | |
630 | 112k | if (granule_bits_read > granule.part_2_3_length) { |
631 | 90 | return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Read too many bits from bit reservoir."_fly_string }; |
632 | 90 | } |
633 | | |
634 | | // 2.4.3.4.6: "If there are more Huffman code bits than necessary to decode 576 values |
635 | | // they are regarded as stuffing bits and discarded." |
636 | 8.92M | for (size_t i = granule_bits_read; i < granule.part_2_3_length; i++) { |
637 | 8.80M | TRY(reservoir.read_bit()); |
638 | 8.80M | } |
639 | | |
640 | 112k | return {}; |
641 | 112k | } |
642 | | |
643 | | void MP3LoaderPlugin::reorder_samples(MP3::Granule& granule, u32 sample_rate) |
644 | 11.2k | { |
645 | 11.2k | float tmp[MP3::granule_size] = {}; |
646 | 11.2k | size_t band_index = 0; |
647 | 11.2k | size_t subband_index = 0; |
648 | | |
649 | 11.2k | auto scale_factor_bands = get_scalefactor_bands(granule, sample_rate); |
650 | | |
651 | 11.2k | if (granule.mixed_block_flag) { |
652 | 57.8k | while (subband_index < 36) { |
653 | 282k | for (size_t frequency_line_index = 0; frequency_line_index < scale_factor_bands[band_index].width; frequency_line_index++) { |
654 | 231k | tmp[subband_index] = granule.samples[subband_index]; |
655 | 231k | subband_index++; |
656 | 231k | } |
657 | 51.4k | band_index++; |
658 | 51.4k | } |
659 | 6.42k | } |
660 | | |
661 | 137k | while (subband_index < MP3::granule_size && band_index <= 36) { |
662 | 2.20M | for (size_t frequency_line_index = 0; frequency_line_index < scale_factor_bands[band_index].width; frequency_line_index++) { |
663 | 2.07M | tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 0].start + frequency_line_index]; |
664 | 2.07M | tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 1].start + frequency_line_index]; |
665 | 2.07M | tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 2].start + frequency_line_index]; |
666 | 2.07M | } |
667 | 126k | band_index += 3; |
668 | 126k | } |
669 | | |
670 | 6.46M | for (size_t i = 0; i < MP3::granule_size; i++) |
671 | 6.45M | granule.samples[i] = tmp[i]; |
672 | 11.2k | } |
673 | | |
674 | | void MP3LoaderPlugin::reduce_alias(MP3::Granule& granule, size_t max_subband_index) |
675 | 107k | { |
676 | 3.24M | for (size_t subband = 0; subband < max_subband_index - 18; subband += 18) { |
677 | 28.2M | for (size_t i = 0; i < 8; i++) { |
678 | 25.0M | size_t const idx1 = subband + 17 - i; |
679 | 25.0M | size_t const idx2 = subband + 18 + i; |
680 | 25.0M | auto const d1 = granule.samples[idx1]; |
681 | 25.0M | auto const d2 = granule.samples[idx2]; |
682 | 25.0M | granule.samples[idx1] = d1 * MP3::Tables::AliasReductionCs[i] - d2 * MP3::Tables::AliasReductionCa[i]; |
683 | 25.0M | granule.samples[idx2] = d2 * MP3::Tables::AliasReductionCs[i] + d1 * MP3::Tables::AliasReductionCa[i]; |
684 | 25.0M | } |
685 | 3.13M | } |
686 | 107k | } |
687 | | |
688 | | void MP3LoaderPlugin::process_stereo(MP3::MP3Frame& frame, size_t granule_index) |
689 | 31.9k | { |
690 | 31.9k | size_t band_index_ms_start = 0; |
691 | 31.9k | size_t band_index_ms_end = 0; |
692 | 31.9k | size_t band_index_intensity_start = 0; |
693 | 31.9k | size_t band_index_intensity_end = 0; |
694 | 31.9k | auto& granule_left = frame.channels[0].granules[granule_index]; |
695 | 31.9k | auto& granule_right = frame.channels[1].granules[granule_index]; |
696 | | |
697 | 31.9k | auto get_last_nonempty_band = [](Span<float> samples, ReadonlySpan<MP3::Tables::ScaleFactorBand> bands) -> size_t { |
698 | 8.59k | size_t last_nonempty_band = 0; |
699 | | |
700 | 233k | for (size_t i = 0; i < bands.size(); i++) { |
701 | 225k | bool is_empty = true; |
702 | 4.74M | for (size_t l = bands[i].start; l < bands[i].end; l++) { |
703 | 4.54M | if (samples[l] != 0) { |
704 | 16.3k | is_empty = false; |
705 | 16.3k | break; |
706 | 16.3k | } |
707 | 4.54M | } |
708 | 225k | if (!is_empty) |
709 | 16.3k | last_nonempty_band = i; |
710 | 225k | } |
711 | | |
712 | 8.59k | return last_nonempty_band; |
713 | 8.59k | }; |
714 | | |
715 | 360k | auto process_ms_stereo = [&](MP3::Tables::ScaleFactorBand const& band) { |
716 | 360k | float const SQRT_2 = AK::sqrt(2.0); |
717 | 8.62M | for (size_t i = band.start; i <= band.end; i++) { |
718 | 8.26M | float const m = granule_left.samples[i]; |
719 | 8.26M | float const s = granule_right.samples[i]; |
720 | 8.26M | granule_left.samples[i] = (m + s) / SQRT_2; |
721 | 8.26M | granule_right.samples[i] = (m - s) / SQRT_2; |
722 | 8.26M | } |
723 | 360k | }; |
724 | | |
725 | 182k | auto process_intensity_stereo = [&](MP3::Tables::ScaleFactorBand const& band, float intensity_stereo_ratio) { |
726 | 4.60M | for (size_t i = band.start; i <= band.end; i++) { |
727 | | // Superflous empty scale factor band. |
728 | 4.42M | if (i >= MP3::granule_size) |
729 | 605 | continue; |
730 | 4.42M | float const sample_left = granule_left.samples[i]; |
731 | 4.42M | float const coeff_l = intensity_stereo_ratio / (1 + intensity_stereo_ratio); |
732 | 4.42M | float const coeff_r = 1 / (1 + intensity_stereo_ratio); |
733 | 4.42M | granule_left.samples[i] = sample_left * coeff_l; |
734 | 4.42M | granule_right.samples[i] = sample_left * coeff_r; |
735 | 4.42M | } |
736 | 182k | }; |
737 | | |
738 | 31.9k | auto scale_factor_bands = get_scalefactor_bands(granule_right, frame.header.samplerate); |
739 | | |
740 | 31.9k | if (has_flag(frame.header.mode_extension, MP3::ModeExtension::MsStereo)) { |
741 | 18.0k | band_index_ms_start = 0; |
742 | 18.0k | band_index_ms_end = scale_factor_bands.size(); |
743 | 18.0k | } |
744 | | |
745 | 31.9k | if (has_flag(frame.header.mode_extension, MP3::ModeExtension::IntensityStereo)) { |
746 | 8.59k | band_index_intensity_start = get_last_nonempty_band(granule_right.samples, scale_factor_bands); |
747 | 8.59k | band_index_intensity_end = scale_factor_bands.size(); |
748 | 8.59k | band_index_ms_end = band_index_intensity_start; |
749 | 8.59k | } |
750 | | |
751 | 380k | for (size_t band_index = band_index_ms_start; band_index < band_index_ms_end; band_index++) { |
752 | 348k | process_ms_stereo(scale_factor_bands[band_index]); |
753 | 348k | } |
754 | | |
755 | 226k | for (size_t band_index = band_index_intensity_start; band_index < band_index_intensity_end; band_index++) { |
756 | 194k | auto const intensity_stereo_position = frame.channels[1].scale_factors[band_index]; |
757 | 194k | if (intensity_stereo_position == 7) { |
758 | 12.0k | if (has_flag(frame.header.mode_extension, MP3::ModeExtension::MsStereo)) |
759 | 11.7k | process_ms_stereo(scale_factor_bands[band_index]); |
760 | 12.0k | continue; |
761 | 12.0k | } |
762 | 182k | float const intensity_stereo_ratio = AK::tan(intensity_stereo_position * AK::Pi<float> / 12); |
763 | 182k | process_intensity_stereo(scale_factor_bands[band_index], intensity_stereo_ratio); |
764 | 182k | } |
765 | 31.9k | } |
766 | | |
767 | | void MP3LoaderPlugin::transform_samples_to_time(Array<float, MP3::granule_size> const& input, size_t input_offset, Array<float, 36>& output, MP3::BlockType block_type) |
768 | 3.56M | { |
769 | 3.56M | if (block_type == MP3::BlockType::Short) { |
770 | 340k | size_t const N = 12; |
771 | 340k | Array<float, N * 3> temp_out; |
772 | 340k | Array<float, N / 2> temp_in; |
773 | | |
774 | 2.38M | for (size_t k = 0; k < N / 2; k++) |
775 | 2.04M | temp_in[k] = input[input_offset + 3 * k + 0]; |
776 | 340k | s_mdct_12.transform(temp_in, Span<float>(temp_out).slice(0, N)); |
777 | 4.42M | for (size_t i = 0; i < N; i++) |
778 | 4.08M | temp_out[i + 0] *= MP3::Tables::WindowBlockTypeShort[i]; |
779 | | |
780 | 2.38M | for (size_t k = 0; k < N / 2; k++) |
781 | 2.04M | temp_in[k] = input[input_offset + 3 * k + 1]; |
782 | 340k | s_mdct_12.transform(temp_in, Span<float>(temp_out).slice(12, N)); |
783 | 4.42M | for (size_t i = 0; i < N; i++) |
784 | 4.08M | temp_out[i + 12] *= MP3::Tables::WindowBlockTypeShort[i]; |
785 | | |
786 | 2.38M | for (size_t k = 0; k < N / 2; k++) |
787 | 2.04M | temp_in[k] = input[input_offset + 3 * k + 2]; |
788 | 340k | s_mdct_12.transform(temp_in, Span<float>(temp_out).slice(24, N)); |
789 | 4.42M | for (size_t i = 0; i < N; i++) |
790 | 4.08M | temp_out[i + 24] *= MP3::Tables::WindowBlockTypeShort[i]; |
791 | | |
792 | 340k | Span<float> idmct1 = Span<float>(temp_out).slice(0, 12); |
793 | 340k | Span<float> idmct2 = Span<float>(temp_out).slice(12, 12); |
794 | 340k | Span<float> idmct3 = Span<float>(temp_out).slice(24, 12); |
795 | 2.38M | for (size_t i = 0; i < 6; i++) |
796 | 2.04M | output[i] = 0; |
797 | 2.38M | for (size_t i = 6; i < 12; i++) |
798 | 2.04M | output[i] = idmct1[i - 6]; |
799 | 2.38M | for (size_t i = 12; i < 18; i++) |
800 | 2.04M | output[i] = idmct1[i - 6] + idmct2[i - 12]; |
801 | 2.38M | for (size_t i = 18; i < 24; i++) |
802 | 2.04M | output[i] = idmct2[i - 12] + idmct3[i - 18]; |
803 | 2.38M | for (size_t i = 24; i < 30; i++) |
804 | 2.04M | output[i] = idmct3[i - 18]; |
805 | 2.38M | for (size_t i = 30; i < 36; i++) |
806 | 2.04M | output[i] = 0; |
807 | | |
808 | 3.22M | } else { |
809 | 3.22M | s_mdct_36.transform(ReadonlySpan<float>(input).slice(input_offset, 18), output); |
810 | 119M | for (size_t i = 0; i < 36; i++) { |
811 | 116M | switch (block_type) { |
812 | 110M | case MP3::BlockType::Normal: |
813 | 110M | output[i] *= MP3::Tables::WindowBlockTypeNormal[i]; |
814 | 110M | break; |
815 | 1.38M | case MP3::BlockType::Start: |
816 | 1.38M | output[i] *= MP3::Tables::WindowBlockTypeStart[i]; |
817 | 1.38M | break; |
818 | 3.77M | case MP3::BlockType::End: |
819 | 3.77M | output[i] *= MP3::Tables::WindowBlockTypeEnd[i]; |
820 | 3.77M | break; |
821 | 0 | case MP3::BlockType::Short: |
822 | 0 | VERIFY_NOT_REACHED(); |
823 | 0 | break; |
824 | 116M | } |
825 | 116M | } |
826 | 3.22M | } |
827 | 3.56M | } |
828 | | |
829 | | // ISO/IEC 11172-3 (Figure A.2) |
830 | | void MP3LoaderPlugin::synthesis(Array<float, 1024>& V, Array<float, 32>& samples, Array<float, 32>& result) |
831 | 2.00M | { |
832 | 1.92G | for (size_t i = 1023; i >= 64; i--) { |
833 | 1.92G | V[i] = V[i - 64]; |
834 | 1.92G | } |
835 | | |
836 | 130M | for (size_t i = 0; i < 64; i++) { |
837 | 128M | V[i] = 0; |
838 | 4.23G | for (size_t k = 0; k < 32; k++) { |
839 | 4.10G | float const N = MP3::Tables::SynthesisSubbandFilterCoefficients[i][k]; |
840 | 4.10G | V[i] += N * samples[k]; |
841 | 4.10G | } |
842 | 128M | } |
843 | | |
844 | 2.00M | Array<float, 512> U; |
845 | 18.0M | for (size_t i = 0; i < 8; i++) { |
846 | 529M | for (size_t j = 0; j < 32; j++) { |
847 | 513M | U[i * 64 + j] = V[i * 128 + j]; |
848 | 513M | U[i * 64 + 32 + j] = V[i * 128 + 96 + j]; |
849 | 513M | } |
850 | 16.0M | } |
851 | | |
852 | 2.00M | Array<float, 512> W; |
853 | 1.02G | for (size_t i = 0; i < 512; i++) { |
854 | 1.02G | W[i] = U[i] * MP3::Tables::WindowSynthesis[i]; |
855 | 1.02G | } |
856 | | |
857 | 66.1M | for (size_t j = 0; j < 32; j++) { |
858 | 64.1M | result[j] = 0; |
859 | 1.09G | for (size_t k = 0; k < 16; k++) { |
860 | 1.02G | result[j] += W[j + 32 * k]; |
861 | 1.02G | } |
862 | 64.1M | } |
863 | 2.00M | } |
864 | | |
865 | | ReadonlySpan<MP3::Tables::ScaleFactorBand> MP3LoaderPlugin::get_scalefactor_bands(MP3::Granule const& granule, int samplerate) |
866 | 268k | { |
867 | 268k | switch (granule.block_type) { |
868 | 38.5k | case MP3::BlockType::Short: |
869 | 38.5k | switch (samplerate) { |
870 | 9.10k | case 32000: |
871 | 9.10k | return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed32000 : MP3::Tables::ScaleFactorBandShort32000; |
872 | 15.4k | case 44100: |
873 | 15.4k | return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed44100 : MP3::Tables::ScaleFactorBandShort44100; |
874 | 14.0k | case 48000: |
875 | 14.0k | return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed48000 : MP3::Tables::ScaleFactorBandShort48000; |
876 | 38.5k | } |
877 | 0 | break; |
878 | 218k | case MP3::BlockType::Normal: |
879 | 218k | [[fallthrough]]; |
880 | 221k | case MP3::BlockType::Start: |
881 | 221k | [[fallthrough]]; |
882 | 229k | case MP3::BlockType::End: |
883 | 229k | switch (samplerate) { |
884 | 35.2k | case 32000: |
885 | 35.2k | return MP3::Tables::ScaleFactorBandLong32000; |
886 | 22.6k | case 44100: |
887 | 22.6k | return MP3::Tables::ScaleFactorBandLong44100; |
888 | 171k | case 48000: |
889 | 171k | return MP3::Tables::ScaleFactorBandLong48000; |
890 | 229k | } |
891 | 268k | } |
892 | 0 | VERIFY_NOT_REACHED(); |
893 | 0 | } |
894 | | |
895 | | } |