Serenity Operating System
at master 343 lines 13 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "WavLoader.h" 9#include "LoaderError.h" 10#include <AK/Debug.h> 11#include <AK/Endian.h> 12#include <AK/FixedArray.h> 13#include <AK/MemoryStream.h> 14#include <AK/NumericLimits.h> 15#include <AK/Try.h> 16#include <LibCore/File.h> 17 18namespace Audio { 19 20static constexpr size_t const maximum_wav_size = 1 * GiB; // FIXME: is there a more appropriate size limit? 21 22WavLoaderPlugin::WavLoaderPlugin(NonnullOwnPtr<SeekableStream> stream) 23 : LoaderPlugin(move(stream)) 24{ 25} 26 27Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> WavLoaderPlugin::create(StringView path) 28{ 29 auto stream = LOADER_TRY(Core::BufferedFile::create(LOADER_TRY(Core::File::open(path, Core::File::OpenMode::Read)))); 30 auto loader = make<WavLoaderPlugin>(move(stream)); 31 32 LOADER_TRY(loader->initialize()); 33 34 return loader; 35} 36 37Result<NonnullOwnPtr<WavLoaderPlugin>, LoaderError> WavLoaderPlugin::create(Bytes buffer) 38{ 39 auto stream = LOADER_TRY(try_make<FixedMemoryStream>(buffer)); 40 auto loader = make<WavLoaderPlugin>(move(stream)); 41 42 LOADER_TRY(loader->initialize()); 43 44 return loader; 45} 46 47MaybeLoaderError WavLoaderPlugin::initialize() 48{ 49 LOADER_TRY(parse_header()); 50 51 return {}; 52} 53 54template<typename SampleReader> 55MaybeLoaderError WavLoaderPlugin::read_samples_from_stream(Stream& stream, SampleReader read_sample, FixedArray<Sample>& samples) const 56{ 57 switch (m_num_channels) { 58 case 1: 59 for (auto& sample : samples) 60 sample = Sample(LOADER_TRY(read_sample(stream))); 61 break; 62 case 2: 63 for (auto& sample : samples) { 64 auto left_channel_sample = LOADER_TRY(read_sample(stream)); 65 auto right_channel_sample = LOADER_TRY(read_sample(stream)); 66 sample = Sample(left_channel_sample, right_channel_sample); 67 } 68 break; 69 default: 70 VERIFY_NOT_REACHED(); 71 } 72 return {}; 73} 74 75// There's no i24 type + we need to do the endianness conversion manually anyways. 76static ErrorOr<double> read_sample_int24(Stream& stream) 77{ 78 i32 sample1 = TRY(stream.read_value<u8>()); 79 i32 sample2 = TRY(stream.read_value<u8>()); 80 i32 sample3 = TRY(stream.read_value<u8>()); 81 82 i32 value = 0; 83 value = sample1; 84 value |= sample2 << 8; 85 value |= sample3 << 16; 86 // Sign extend the value, as it can currently not have the correct sign. 87 value = (value << 8) >> 8; 88 // Range of value is now -2^23 to 2^23-1 and we can rescale normally. 89 return static_cast<double>(value) / static_cast<double>((1 << 23) - 1); 90} 91 92template<typename T> 93static ErrorOr<double> read_sample(Stream& stream) 94{ 95 T sample { 0 }; 96 TRY(stream.read_until_filled(Bytes { &sample, sizeof(T) })); 97 // Remap integer samples to normalized floating-point range of -1 to 1. 98 if constexpr (IsIntegral<T>) { 99 if constexpr (NumericLimits<T>::is_signed()) { 100 // Signed integer samples are centered around zero, so this division is enough. 101 return static_cast<double>(AK::convert_between_host_and_little_endian(sample)) / static_cast<double>(NumericLimits<T>::max()); 102 } else { 103 // Unsigned integer samples, on the other hand, need to be shifted to center them around zero. 104 // The first division therefore remaps to the range 0 to 2. 105 return static_cast<double>(AK::convert_between_host_and_little_endian(sample)) / (static_cast<double>(NumericLimits<T>::max()) / 2.0) - 1.0; 106 } 107 } else { 108 return static_cast<double>(AK::convert_between_host_and_little_endian(sample)); 109 } 110} 111 112LoaderSamples WavLoaderPlugin::samples_from_pcm_data(Bytes const& data, size_t samples_to_read) const 113{ 114 FixedArray<Sample> samples = LOADER_TRY(FixedArray<Sample>::create(samples_to_read)); 115 FixedMemoryStream stream { data }; 116 117 switch (m_sample_format) { 118 case PcmSampleFormat::Uint8: 119 TRY(read_samples_from_stream(stream, read_sample<u8>, samples)); 120 break; 121 case PcmSampleFormat::Int16: 122 TRY(read_samples_from_stream(stream, read_sample<i16>, samples)); 123 break; 124 case PcmSampleFormat::Int24: 125 TRY(read_samples_from_stream(stream, read_sample_int24, samples)); 126 break; 127 case PcmSampleFormat::Float32: 128 TRY(read_samples_from_stream(stream, read_sample<float>, samples)); 129 break; 130 case PcmSampleFormat::Float64: 131 TRY(read_samples_from_stream(stream, read_sample<double>, samples)); 132 break; 133 default: 134 VERIFY_NOT_REACHED(); 135 } 136 137 return samples; 138} 139 140ErrorOr<Vector<FixedArray<Sample>>, LoaderError> WavLoaderPlugin::load_chunks(size_t samples_to_read_from_input) 141{ 142 auto remaining_samples = m_total_samples - m_loaded_samples; 143 if (remaining_samples <= 0) 144 return Vector<FixedArray<Sample>> {}; 145 146 // One "sample" contains data from all channels. 147 // In the Wave spec, this is also called a block. 148 size_t bytes_per_sample 149 = m_num_channels * pcm_bits_per_sample(m_sample_format) / 8; 150 151 auto samples_to_read = min(samples_to_read_from_input, remaining_samples); 152 auto bytes_to_read = samples_to_read * bytes_per_sample; 153 154 dbgln_if(AWAVLOADER_DEBUG, "Read {} bytes WAV with num_channels {} sample rate {}, " 155 "bits per sample {}, sample format {}", 156 bytes_to_read, m_num_channels, m_sample_rate, 157 pcm_bits_per_sample(m_sample_format), sample_format_name(m_sample_format)); 158 159 auto sample_data = LOADER_TRY(ByteBuffer::create_zeroed(bytes_to_read)); 160 LOADER_TRY(m_stream->read_until_filled(sample_data.bytes())); 161 162 // m_loaded_samples should contain the amount of actually loaded samples 163 m_loaded_samples += samples_to_read; 164 Vector<FixedArray<Sample>> samples; 165 TRY(samples.try_append(TRY(samples_from_pcm_data(sample_data.bytes(), samples_to_read)))); 166 return samples; 167} 168 169MaybeLoaderError WavLoaderPlugin::seek(int sample_index) 170{ 171 dbgln_if(AWAVLOADER_DEBUG, "seek sample_index {}", sample_index); 172 if (sample_index < 0 || sample_index >= static_cast<int>(m_total_samples)) 173 return LoaderError { LoaderError::Category::Internal, m_loaded_samples, "Seek outside the sample range" }; 174 175 size_t sample_offset = m_byte_offset_of_data_samples + static_cast<size_t>(sample_index * m_num_channels * (pcm_bits_per_sample(m_sample_format) / 8)); 176 177 LOADER_TRY(m_stream->seek(sample_offset, SeekMode::SetPosition)); 178 179 m_loaded_samples = sample_index; 180 return {}; 181} 182 183// Specification reference: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html 184MaybeLoaderError WavLoaderPlugin::parse_header() 185{ 186 bool ok = true; 187 size_t bytes_read = 0; 188 189 auto read_u8 = [&]() -> ErrorOr<u8, LoaderError> { 190 u8 value = LOADER_TRY(m_stream->read_value<LittleEndian<u8>>()); 191 bytes_read += 1; 192 return value; 193 }; 194 195 auto read_u16 = [&]() -> ErrorOr<u16, LoaderError> { 196 u16 value = LOADER_TRY(m_stream->read_value<LittleEndian<u16>>()); 197 bytes_read += 2; 198 return value; 199 }; 200 201 auto read_u32 = [&]() -> ErrorOr<u32, LoaderError> { 202 u32 value = LOADER_TRY(m_stream->read_value<LittleEndian<u32>>()); 203 bytes_read += 4; 204 return value; 205 }; 206 207#define CHECK_OK(category, msg) \ 208 do { \ 209 if (!ok) \ 210 return LoaderError { category, DeprecatedString::formatted("Parsing failed: {}", msg) }; \ 211 } while (0) 212 213 u32 riff = TRY(read_u32()); 214 ok = ok && riff == 0x46464952; // "RIFF" 215 CHECK_OK(LoaderError::Category::Format, "RIFF header"); 216 217 u32 sz = TRY(read_u32()); 218 ok = ok && sz < maximum_wav_size; 219 CHECK_OK(LoaderError::Category::Format, "File size"); 220 221 u32 wave = TRY(read_u32()); 222 ok = ok && wave == 0x45564157; // "WAVE" 223 CHECK_OK(LoaderError::Category::Format, "WAVE header"); 224 225 u32 fmt_id = TRY(read_u32()); 226 ok = ok && fmt_id == 0x20746D66; // "fmt " 227 CHECK_OK(LoaderError::Category::Format, "FMT header"); 228 229 u32 fmt_size = TRY(read_u32()); 230 ok = ok && (fmt_size == 16 || fmt_size == 18 || fmt_size == 40); 231 CHECK_OK(LoaderError::Category::Format, "FMT size"); 232 233 u16 audio_format = TRY(read_u16()); 234 CHECK_OK(LoaderError::Category::Format, "Audio format"); // incomplete read check 235 ok = ok && (audio_format == WAVE_FORMAT_PCM || audio_format == WAVE_FORMAT_IEEE_FLOAT || audio_format == WAVE_FORMAT_EXTENSIBLE); 236 CHECK_OK(LoaderError::Category::Unimplemented, "Audio format PCM/Float"); // value check 237 238 m_num_channels = TRY(read_u16()); 239 ok = ok && (m_num_channels == 1 || m_num_channels == 2); 240 CHECK_OK(LoaderError::Category::Unimplemented, "Channel count"); 241 242 m_sample_rate = TRY(read_u32()); 243 CHECK_OK(LoaderError::Category::IO, "Sample rate"); 244 245 TRY(read_u32()); 246 CHECK_OK(LoaderError::Category::IO, "Data rate"); 247 248 u16 block_size_bytes = TRY(read_u16()); 249 CHECK_OK(LoaderError::Category::IO, "Block size"); 250 251 u16 bits_per_sample = TRY(read_u16()); 252 CHECK_OK(LoaderError::Category::IO, "Bits per sample"); 253 254 if (audio_format == WAVE_FORMAT_EXTENSIBLE) { 255 ok = ok && (fmt_size == 40); 256 CHECK_OK(LoaderError::Category::Format, "Extensible fmt size"); // value check 257 258 // Discard everything until the GUID. 259 // We've already read 16 bytes from the stream. The GUID starts in another 8 bytes. 260 TRY(read_u32()); 261 TRY(read_u32()); 262 CHECK_OK(LoaderError::Category::IO, "Discard until GUID"); 263 264 // Get the underlying audio format from the first two bytes of GUID 265 u16 guid_subformat = TRY(read_u16()); 266 ok = ok && (guid_subformat == WAVE_FORMAT_PCM || guid_subformat == WAVE_FORMAT_IEEE_FLOAT); 267 CHECK_OK(LoaderError::Category::Unimplemented, "GUID SubFormat"); 268 269 audio_format = guid_subformat; 270 } 271 272 if (audio_format == WAVE_FORMAT_PCM) { 273 ok = ok && (bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24); 274 CHECK_OK(LoaderError::Category::Unimplemented, "Bits per sample (PCM)"); // value check 275 276 // We only support 8-24 bit audio right now because other formats are uncommon 277 if (bits_per_sample == 8) { 278 m_sample_format = PcmSampleFormat::Uint8; 279 } else if (bits_per_sample == 16) { 280 m_sample_format = PcmSampleFormat::Int16; 281 } else if (bits_per_sample == 24) { 282 m_sample_format = PcmSampleFormat::Int24; 283 } 284 } else if (audio_format == WAVE_FORMAT_IEEE_FLOAT) { 285 ok = ok && (bits_per_sample == 32 || bits_per_sample == 64); 286 CHECK_OK(LoaderError::Category::Unimplemented, "Bits per sample (Float)"); // value check 287 288 // Again, only the common 32 and 64 bit 289 if (bits_per_sample == 32) { 290 m_sample_format = PcmSampleFormat::Float32; 291 } else if (bits_per_sample == 64) { 292 m_sample_format = PcmSampleFormat::Float64; 293 } 294 } 295 296 ok = ok && (block_size_bytes == (m_num_channels * (bits_per_sample / 8))); 297 CHECK_OK(LoaderError::Category::Format, "Block size sanity check"); 298 299 dbgln_if(AWAVLOADER_DEBUG, "WAV format {} at {} bit, {} channels, rate {}Hz ", 300 sample_format_name(m_sample_format), pcm_bits_per_sample(m_sample_format), m_num_channels, m_sample_rate); 301 302 // Read chunks until we find DATA 303 bool found_data = false; 304 u32 data_size = 0; 305 u8 search_byte = 0; 306 while (true) { 307 search_byte = TRY(read_u8()); 308 CHECK_OK(LoaderError::Category::IO, "Reading byte searching for data"); 309 if (search_byte != 0x64) // D 310 continue; 311 312 search_byte = TRY(read_u8()); 313 CHECK_OK(LoaderError::Category::IO, "Reading next byte searching for data"); 314 if (search_byte != 0x61) // A 315 continue; 316 317 u16 search_remaining = TRY(read_u16()); 318 CHECK_OK(LoaderError::Category::IO, "Reading remaining bytes searching for data"); 319 if (search_remaining != 0x6174) // TA 320 continue; 321 322 data_size = TRY(read_u32()); 323 found_data = true; 324 break; 325 } 326 327 ok = ok && found_data; 328 CHECK_OK(LoaderError::Category::Format, "Found no data chunk"); 329 330 ok = ok && data_size < maximum_wav_size; 331 CHECK_OK(LoaderError::Category::Format, "Data was too large"); 332 333 m_total_samples = data_size / block_size_bytes; 334 335 dbgln_if(AWAVLOADER_DEBUG, "WAV data size {}, bytes per sample {}, total samples {}", 336 data_size, 337 block_size_bytes, 338 m_total_samples); 339 340 m_byte_offset_of_data_samples = bytes_read; 341 return {}; 342} 343}