Serenity Operating System
at portability 314 lines 10 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/BufferStream.h> 28#include <AK/OwnPtr.h> 29#include <LibAudio/WavLoader.h> 30#include <LibCore/File.h> 31#include <LibCore/IODeviceStreamReader.h> 32#include <limits> 33 34namespace Audio { 35 36WavLoader::WavLoader(const StringView& path) 37 : m_file(Core::File::construct(path)) 38{ 39 if (!m_file->open(Core::IODevice::ReadOnly)) { 40 m_error_string = String::format("Can't open file: %s", m_file->error_string()); 41 return; 42 } 43 44 if (!parse_header()) 45 return; 46 47 m_resampler = make<ResampleHelper>(m_sample_rate, 44100); 48} 49 50RefPtr<Buffer> WavLoader::get_more_samples(size_t max_bytes_to_read_from_input) 51{ 52#ifdef AWAVLOADER_DEBUG 53 dbgprintf("Read WAV of format PCM with num_channels %u sample rate %u, bits per sample %u\n", m_num_channels, m_sample_rate, m_bits_per_sample); 54#endif 55 56 auto raw_samples = m_file->read(max_bytes_to_read_from_input); 57 if (raw_samples.is_empty()) 58 return nullptr; 59 60 auto buffer = Buffer::from_pcm_data(raw_samples, *m_resampler, m_num_channels, m_bits_per_sample); 61 //Buffer contains normalized samples, but m_loaded_samples should containt the ammount of actually loaded samples 62 m_loaded_samples += static_cast<int>(max_bytes_to_read_from_input) / (m_num_channels * (m_bits_per_sample / 8)); 63 m_loaded_samples = min(m_total_samples, m_loaded_samples); 64 return buffer; 65} 66 67void WavLoader::seek(const int position) 68{ 69 if (position < 0 || position > m_total_samples) 70 return; 71 72 m_loaded_samples = position; 73 m_file->seek(position * m_num_channels * (m_bits_per_sample / 8)); 74} 75 76void WavLoader::reset() 77{ 78 seek(0); 79} 80 81bool WavLoader::parse_header() 82{ 83 Core::IODeviceStreamReader stream(*m_file); 84 85#define CHECK_OK(msg) \ 86 do { \ 87 if (stream.handle_read_failure()) { \ 88 m_error_string = String::format("Premature stream EOF at %s", msg); \ 89 return {}; \ 90 } \ 91 if (!ok) { \ 92 m_error_string = String::format("Parsing failed: %s", msg); \ 93 return {}; \ 94 } else { \ 95 dbgprintf("%s is OK!\n", msg); \ 96 } \ 97 } while (0); 98 99 bool ok = true; 100 u32 riff; 101 stream >> riff; 102 ok = ok && riff == 0x46464952; // "RIFF" 103 CHECK_OK("RIFF header"); 104 105 u32 sz; 106 stream >> sz; 107 ok = ok && sz < 1024 * 1024 * 1024; // arbitrary 108 CHECK_OK("File size"); 109 ASSERT(sz < 1024 * 1024 * 1024); 110 111 u32 wave; 112 stream >> wave; 113 ok = ok && wave == 0x45564157; // "WAVE" 114 CHECK_OK("WAVE header"); 115 116 u32 fmt_id; 117 stream >> fmt_id; 118 ok = ok && fmt_id == 0x20746D66; // "FMT" 119 CHECK_OK("FMT header"); 120 121 u32 fmt_size; 122 stream >> fmt_size; 123 ok = ok && fmt_size == 16; 124 CHECK_OK("FMT size"); 125 ASSERT(fmt_size == 16); 126 127 u16 audio_format; 128 stream >> audio_format; 129 CHECK_OK("Audio format"); // incomplete read check 130 ok = ok && audio_format == 1; // WAVE_FORMAT_PCM 131 ASSERT(audio_format == 1); 132 CHECK_OK("Audio format"); // value check 133 134 stream >> m_num_channels; 135 ok = ok && (m_num_channels == 1 || m_num_channels == 2); 136 CHECK_OK("Channel count"); 137 138 stream >> m_sample_rate; 139 CHECK_OK("Sample rate"); 140 141 u32 byte_rate; 142 stream >> byte_rate; 143 CHECK_OK("Byte rate"); 144 145 u16 block_align; 146 stream >> block_align; 147 CHECK_OK("Block align"); 148 149 stream >> m_bits_per_sample; 150 CHECK_OK("Bits per sample"); // incomplete read check 151 ok = ok && (m_bits_per_sample == 8 || m_bits_per_sample == 16 || m_bits_per_sample == 24); 152 ASSERT(m_bits_per_sample == 8 || m_bits_per_sample == 16 || m_bits_per_sample == 24); 153 CHECK_OK("Bits per sample"); // value check 154 155 // Read chunks until we find DATA 156 bool found_data = false; 157 u32 data_sz = 0; 158 while (true) { 159 u32 chunk_id; 160 stream >> chunk_id; 161 CHECK_OK("Reading chunk ID searching for data"); 162 stream >> data_sz; 163 CHECK_OK("Reading chunk size searching for data"); 164 if (chunk_id == 0x61746164) { // DATA 165 found_data = true; 166 break; 167 } 168 } 169 170 ok = ok && found_data; 171 CHECK_OK("Found no data chunk"); 172 ASSERT(found_data); 173 174 ok = ok && data_sz < INT32_MAX; 175 CHECK_OK("Data was too large"); 176 177 int bytes_per_sample = (m_bits_per_sample / 8) * m_num_channels; 178 m_total_samples = data_sz / bytes_per_sample; 179 180 // Just make sure we're good before we read the data... 181 ASSERT(!stream.handle_read_failure()); 182 183 return true; 184} 185 186ResampleHelper::ResampleHelper(double source, double target) 187 : m_ratio(source / target) 188{ 189} 190 191void ResampleHelper::process_sample(double sample_l, double sample_r) 192{ 193 m_last_sample_l = sample_l; 194 m_last_sample_r = sample_r; 195 m_current_ratio += 1; 196} 197 198bool ResampleHelper::read_sample(double& next_l, double& next_r) 199{ 200 if (m_current_ratio > 0) { 201 m_current_ratio -= m_ratio; 202 next_l = m_last_sample_l; 203 next_r = m_last_sample_r; 204 return true; 205 } 206 207 return false; 208} 209 210template<typename SampleReader> 211static void read_samples_from_stream(BufferStream& stream, SampleReader read_sample, Vector<Sample>& samples, ResampleHelper& resampler, int num_channels) 212{ 213 double norm_l = 0; 214 double norm_r = 0; 215 216 switch (num_channels) { 217 case 1: 218 for (;;) { 219 while (resampler.read_sample(norm_l, norm_r)) { 220 samples.append(Sample(norm_l)); 221 } 222 norm_l = read_sample(stream); 223 224 if (stream.handle_read_failure()) { 225 break; 226 } 227 resampler.process_sample(norm_l, norm_r); 228 } 229 break; 230 case 2: 231 for (;;) { 232 while (resampler.read_sample(norm_l, norm_r)) { 233 samples.append(Sample(norm_l, norm_r)); 234 } 235 norm_l = read_sample(stream); 236 norm_r = read_sample(stream); 237 238 if (stream.handle_read_failure()) { 239 break; 240 } 241 resampler.process_sample(norm_l, norm_r); 242 } 243 break; 244 default: 245 ASSERT_NOT_REACHED(); 246 } 247} 248 249static double read_norm_sample_24(BufferStream& stream) 250{ 251 u8 byte = 0; 252 stream >> byte; 253 u32 sample1 = byte; 254 stream >> byte; 255 u32 sample2 = byte; 256 stream >> byte; 257 u32 sample3 = byte; 258 259 i32 value = 0; 260 value = sample1 << 8; 261 value |= (sample2 << 16); 262 value |= (sample3 << 24); 263 return double(value) / std::numeric_limits<i32>::max(); 264} 265 266static double read_norm_sample_16(BufferStream& stream) 267{ 268 i16 sample = 0; 269 stream >> sample; 270 return double(sample) / std::numeric_limits<i16>::max(); 271} 272 273static double read_norm_sample_8(BufferStream& stream) 274{ 275 u8 sample = 0; 276 stream >> sample; 277 return double(sample) / std::numeric_limits<u8>::max(); 278} 279 280// ### can't const this because BufferStream is non-const 281// perhaps we need a reading class separate from the writing one, that can be 282// entirely consted. 283RefPtr<Buffer> Buffer::from_pcm_data(ByteBuffer& data, ResampleHelper& resampler, int num_channels, int bits_per_sample) 284{ 285 BufferStream stream(data); 286 Vector<Sample> fdata; 287 fdata.ensure_capacity(data.size() / (bits_per_sample / 8)); 288#ifdef AWAVLOADER_DEBUG 289 dbg() << "Reading " << bits_per_sample << " bits and " << num_channels << " channels, total bytes: " << data.size(); 290#endif 291 292 switch (bits_per_sample) { 293 case 8: 294 read_samples_from_stream(stream, read_norm_sample_8, fdata, resampler, num_channels); 295 break; 296 case 16: 297 read_samples_from_stream(stream, read_norm_sample_16, fdata, resampler, num_channels); 298 break; 299 case 24: 300 read_samples_from_stream(stream, read_norm_sample_24, fdata, resampler, num_channels); 301 break; 302 default: 303 ASSERT_NOT_REACHED(); 304 } 305 306 // We should handle this in a better way above, but for now -- 307 // just make sure we're good. Worst case we just write some 0s where they 308 // don't belong. 309 ASSERT(!stream.handle_read_failure()); 310 311 return Buffer::create_with_samples(move(fdata)); 312} 313 314}