QOALoader.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "QOALoader.h"
  7. #include "Loader.h"
  8. #include "LoaderError.h"
  9. #include "QOATypes.h"
  10. #include <AK/Array.h>
  11. #include <AK/Assertions.h>
  12. #include <AK/Endian.h>
  13. #include <AK/FixedArray.h>
  14. #include <AK/MemoryStream.h>
  15. #include <AK/Stream.h>
  16. #include <AK/Types.h>
  17. #include <LibCore/File.h>
  18. namespace Audio {
  19. QOALoaderPlugin::QOALoaderPlugin(NonnullOwnPtr<AK::SeekableStream> stream)
  20. : LoaderPlugin(move(stream))
  21. {
  22. }
  23. Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> QOALoaderPlugin::create(StringView path)
  24. {
  25. auto stream = LOADER_TRY(Core::BufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read))));
  26. auto loader = make<QOALoaderPlugin>(move(stream));
  27. LOADER_TRY(loader->initialize());
  28. return loader;
  29. }
  30. Result<NonnullOwnPtr<QOALoaderPlugin>, LoaderError> QOALoaderPlugin::create(Bytes buffer)
  31. {
  32. auto loader = make<QOALoaderPlugin>(make<FixedMemoryStream>(buffer));
  33. LOADER_TRY(loader->initialize());
  34. return loader;
  35. }
  36. MaybeLoaderError QOALoaderPlugin::initialize()
  37. {
  38. TRY(parse_header());
  39. TRY(reset());
  40. return {};
  41. }
  42. MaybeLoaderError QOALoaderPlugin::parse_header()
  43. {
  44. u32 header_magic = LOADER_TRY(m_stream->read_value<BigEndian<u32>>());
  45. if (header_magic != QOA::magic)
  46. return LoaderError { LoaderError::Category::Format, 0, "QOA header: Magic number must be 'qoaf'" };
  47. m_total_samples = LOADER_TRY(m_stream->read_value<BigEndian<u32>>());
  48. return {};
  49. }
  50. MaybeLoaderError QOALoaderPlugin::load_one_frame(Span<Sample>& target, IsFirstFrame is_first_frame)
  51. {
  52. QOA::FrameHeader header = LOADER_TRY(m_stream->read_value<QOA::FrameHeader>());
  53. if (header.num_channels > 8)
  54. dbgln("QOALoader: Warning: QOA frame at {} has more than 8 channels ({}), this is not supported by the reference implementation.", LOADER_TRY(m_stream->tell()) - sizeof(QOA::FrameHeader), header.num_channels);
  55. if (header.num_channels == 0)
  56. return LoaderError { LoaderError::Category::Format, LOADER_TRY(m_stream->tell()), "QOA frame: Number of channels must be greater than 0" };
  57. if (header.sample_count > QOA::max_frame_samples)
  58. return LoaderError { LoaderError::Category::Format, LOADER_TRY(m_stream->tell()), "QOA frame: Too many samples in frame" };
  59. // We weren't given a large enough buffer; signal that we didn't write anything and return.
  60. if (header.sample_count > target.size()) {
  61. target = target.trim(0);
  62. LOADER_TRY(m_stream->seek(-sizeof(QOA::frame_header_size), AK::SeekMode::FromCurrentPosition));
  63. return {};
  64. }
  65. target = target.trim(header.sample_count);
  66. auto lms_states = LOADER_TRY(FixedArray<QOA::LMSState>::create(header.num_channels));
  67. for (size_t channel = 0; channel < header.num_channels; ++channel) {
  68. auto history_packed = LOADER_TRY(m_stream->read_value<BigEndian<u64>>());
  69. auto weights_packed = LOADER_TRY(m_stream->read_value<BigEndian<u64>>());
  70. lms_states[channel] = { history_packed, weights_packed };
  71. }
  72. // We pre-allocate very large arrays here, but that's the last allocation of the QOA loader!
  73. // Everything else is just shuffling data around.
  74. // (We will also be using all of the arrays in every frame but the last one.)
  75. auto channels = LOADER_TRY((FixedArray<Array<i16, QOA::max_frame_samples>>::create(header.num_channels)));
  76. // There's usually (and at maximum) 256 slices per channel, but less at the very end.
  77. // If the final slice would be partial, we still need to decode it; integer division would tell us that this final slice doesn't exist.
  78. auto const slice_count = static_cast<size_t>(ceil(static_cast<double>(header.sample_count) / static_cast<double>(QOA::slice_samples)));
  79. VERIFY(slice_count <= QOA::max_slices_per_frame);
  80. // Observe the loop nesting: Slices are channel-interleaved.
  81. for (size_t slice = 0; slice < slice_count; ++slice) {
  82. for (size_t channel = 0; channel < header.num_channels; ++channel) {
  83. auto slice_samples = channels[channel].span().slice(slice * QOA::slice_samples, QOA::slice_samples);
  84. TRY(read_one_slice(lms_states[channel], slice_samples));
  85. }
  86. }
  87. if (is_first_frame == IsFirstFrame::Yes) {
  88. m_num_channels = header.num_channels;
  89. m_sample_rate = header.sample_rate;
  90. } else {
  91. if (m_sample_rate != header.sample_rate)
  92. return LoaderError { LoaderError::Category::Unimplemented, LOADER_TRY(m_stream->tell()), "QOA: Differing sample rate in non-initial frame" };
  93. if (m_num_channels != header.num_channels)
  94. m_has_uniform_channel_count = false;
  95. }
  96. switch (header.num_channels) {
  97. case 1:
  98. for (size_t sample = 0; sample < header.sample_count; ++sample)
  99. target[sample] = Sample { static_cast<float>(channels[0][sample]) / static_cast<float>(NumericLimits<i16>::max()) };
  100. break;
  101. // FIXME: Combine surround channels sensibly, FlacLoader has the same simplification at the moment.
  102. case 2:
  103. case 3:
  104. case 4:
  105. case 5:
  106. case 6:
  107. case 7:
  108. case 8:
  109. default:
  110. for (size_t sample = 0; sample < header.sample_count; ++sample) {
  111. target[sample] = {
  112. static_cast<float>(channels[0][sample]) / static_cast<float>(NumericLimits<i16>::max()),
  113. static_cast<float>(channels[1][sample]) / static_cast<float>(NumericLimits<i16>::max()),
  114. };
  115. }
  116. break;
  117. }
  118. return {};
  119. }
  120. ErrorOr<Vector<FixedArray<Sample>>, LoaderError> QOALoaderPlugin::load_chunks(size_t samples_to_read_from_input)
  121. {
  122. ssize_t const remaining_samples = static_cast<ssize_t>(m_total_samples - m_loaded_samples);
  123. if (remaining_samples <= 0)
  124. return Vector<FixedArray<Sample>> {};
  125. size_t const samples_to_read = min(samples_to_read_from_input, remaining_samples);
  126. auto is_first_frame = m_loaded_samples == 0 ? IsFirstFrame::Yes : IsFirstFrame::No;
  127. Vector<FixedArray<Sample>> frames;
  128. size_t current_loaded_samples = 0;
  129. while (current_loaded_samples < samples_to_read) {
  130. auto samples = LOADER_TRY(FixedArray<Sample>::create(QOA::max_frame_samples));
  131. auto slice_to_load_into = samples.span();
  132. TRY(this->load_one_frame(slice_to_load_into, is_first_frame));
  133. is_first_frame = IsFirstFrame::No;
  134. VERIFY(slice_to_load_into.size() <= QOA::max_frame_samples);
  135. current_loaded_samples += slice_to_load_into.size();
  136. if (slice_to_load_into.size() != samples.size()) {
  137. auto smaller_samples = LOADER_TRY(FixedArray<Sample>::create(slice_to_load_into));
  138. samples.swap(smaller_samples);
  139. }
  140. LOADER_TRY(frames.try_append(move(samples)));
  141. if (slice_to_load_into.size() != samples.size())
  142. break;
  143. }
  144. m_loaded_samples += current_loaded_samples;
  145. return frames;
  146. }
  147. MaybeLoaderError QOALoaderPlugin::reset()
  148. {
  149. LOADER_TRY(m_stream->seek(QOA::header_size, AK::SeekMode::SetPosition));
  150. m_loaded_samples = 0;
  151. // Read the first frame, then seek back to the beginning. This is necessary since the first frame contains the sample rate and channel count.
  152. auto frame_samples = LOADER_TRY(FixedArray<Sample>::create(QOA::max_frame_samples));
  153. auto span = frame_samples.span();
  154. LOADER_TRY(load_one_frame(span, IsFirstFrame::Yes));
  155. LOADER_TRY(m_stream->seek(QOA::header_size, AK::SeekMode::SetPosition));
  156. m_loaded_samples = 0;
  157. return {};
  158. }
  159. MaybeLoaderError QOALoaderPlugin::seek(int sample_index)
  160. {
  161. if (sample_index == 0 && m_loaded_samples == 0)
  162. return {};
  163. // A QOA file consists of 8 bytes header followed by a number of usually fixed-size frames.
  164. // This fixed bitrate allows us to seek in constant time.
  165. if (!m_has_uniform_channel_count)
  166. return LoaderError { LoaderError::Category::Unimplemented, LOADER_TRY(m_stream->tell()), "QOA with non-uniform channel count is currently not seekable"sv };
  167. /// FIXME: Change the Loader API to use size_t.
  168. VERIFY(sample_index >= 0);
  169. // We seek to the frame "before"; i.e. the frame that contains that sample.
  170. auto const frame_of_sample = static_cast<size_t>(AK::floor<double>(static_cast<double>(sample_index) / static_cast<double>(QOA::max_frame_samples)));
  171. auto const frame_size = QOA::frame_header_size + m_num_channels * (QOA::lms_state_size + sizeof(QOA::PackedSlice) * QOA::max_slices_per_frame);
  172. auto const byte_index = QOA::header_size + frame_of_sample * frame_size;
  173. LOADER_TRY(m_stream->seek(byte_index, AK::SeekMode::SetPosition));
  174. m_loaded_samples = frame_of_sample * QOA::max_frame_samples;
  175. return {};
  176. }
  177. MaybeLoaderError QOALoaderPlugin::read_one_slice(QOA::LMSState& lms_state, Span<i16>& samples)
  178. {
  179. VERIFY(samples.size() == QOA::slice_samples);
  180. auto packed_slice = LOADER_TRY(m_stream->read_value<BigEndian<u64>>());
  181. auto unpacked_slice = unpack_slice(packed_slice);
  182. for (size_t i = 0; i < QOA::slice_samples; ++i) {
  183. auto const residual = unpacked_slice.residuals[i];
  184. auto const predicted = lms_state.predict();
  185. auto const dequantized = QOA::dequantization_table[unpacked_slice.scale_factor_index][residual];
  186. auto const reconstructed = clamp(predicted + dequantized, QOA::sample_minimum, QOA::sample_maximum);
  187. samples[i] = static_cast<i16>(reconstructed);
  188. lms_state.update(reconstructed, dequantized);
  189. }
  190. return {};
  191. }
  192. QOA::UnpackedSlice QOALoaderPlugin::unpack_slice(QOA::PackedSlice packed_slice)
  193. {
  194. size_t const scale_factor_index = (packed_slice >> 60) & 0b1111;
  195. Array<u8, 20> residuals = {};
  196. auto shifted_slice = packed_slice << 4;
  197. for (size_t i = 0; i < QOA::slice_samples; ++i) {
  198. residuals[i] = static_cast<u8>((shifted_slice >> 61) & 0b111);
  199. shifted_slice <<= 3;
  200. }
  201. return {
  202. .scale_factor_index = scale_factor_index,
  203. .residuals = residuals,
  204. };
  205. }
  206. i16 QOALoaderPlugin::qoa_divide(i16 value, i16 scale_factor)
  207. {
  208. auto const reciprocal = QOA::reciprocal_table[scale_factor];
  209. auto const n = (value * reciprocal + (1 << 15)) >> 16;
  210. // Rounding away from zero gives better quantization for small values.
  211. auto const n_rounded = n + (static_cast<int>(value > 0) - static_cast<int>(value < 0)) - (static_cast<int>(n > 0) - static_cast<int>(n < 0));
  212. return static_cast<i16>(n_rounded);
  213. }
  214. }