Serenity Operating System
at master 115 lines 3.4 kB view raw
1/* 2 * Copyright (c) 2020, William McPherson <willmcpherson2@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibAudio/WavWriter.h> 8#include <LibCore/DeprecatedFile.h> 9 10namespace Audio { 11 12WavWriter::WavWriter(StringView path, int sample_rate, u16 num_channels, u16 bits_per_sample) 13 : m_sample_rate(sample_rate) 14 , m_num_channels(num_channels) 15 , m_bits_per_sample(bits_per_sample) 16{ 17 set_file(path); 18} 19 20WavWriter::WavWriter(int sample_rate, u16 num_channels, u16 bits_per_sample) 21 : m_sample_rate(sample_rate) 22 , m_num_channels(num_channels) 23 , m_bits_per_sample(bits_per_sample) 24{ 25} 26 27WavWriter::~WavWriter() 28{ 29 if (!m_finalized) 30 finalize(); 31} 32 33void WavWriter::set_file(StringView path) 34{ 35 m_file = Core::DeprecatedFile::construct(path); 36 if (!m_file->open(Core::OpenMode::ReadWrite)) { 37 m_error_string = DeprecatedString::formatted("Can't open file: {}", m_file->error_string()); 38 return; 39 } 40 m_file->seek(44); 41 m_finalized = false; 42} 43 44void WavWriter::write_samples(Span<Sample> samples) 45{ 46 m_data_sz += samples.size() * sizeof(Sample); 47 48 for (auto const& sample : samples) { 49 // FIXME: This only really works for 16-bit samples. 50 u16 left = static_cast<i16>(sample.left * static_cast<float>(1 << m_bits_per_sample)); 51 u16 right = static_cast<i16>(sample.right * static_cast<float>(1 << m_bits_per_sample)); 52 // FIXME: This ignores endianness. 53 m_file->write(bit_cast<u8 const*>(&left), sizeof(u16)); 54 m_file->write(bit_cast<u8 const*>(&right), sizeof(u16)); 55 } 56} 57 58void WavWriter::finalize() 59{ 60 VERIFY(!m_finalized); 61 m_finalized = true; 62 if (m_file) { 63 m_file->seek(0); 64 write_header(); 65 m_file->close(); 66 } 67 m_data_sz = 0; 68} 69 70void WavWriter::write_header() 71{ 72 // "RIFF" 73 static u32 riff = 0x46464952; 74 m_file->write(reinterpret_cast<u8*>(&riff), sizeof(riff)); 75 76 // Size of data + (size of header - previous field - this field) 77 u32 sz = m_data_sz + (44 - 4 - 4); 78 m_file->write(reinterpret_cast<u8*>(&sz), sizeof(sz)); 79 80 // "WAVE" 81 static u32 wave = 0x45564157; 82 m_file->write(reinterpret_cast<u8*>(&wave), sizeof(wave)); 83 84 // "fmt " 85 static u32 fmt_id = 0x20746D66; 86 m_file->write(reinterpret_cast<u8*>(&fmt_id), sizeof(fmt_id)); 87 88 // Size of the next 6 fields 89 static u32 fmt_size = 16; 90 m_file->write(reinterpret_cast<u8*>(&fmt_size), sizeof(fmt_size)); 91 92 // 1 for PCM 93 static u16 audio_format = 1; 94 m_file->write(reinterpret_cast<u8*>(&audio_format), sizeof(audio_format)); 95 96 m_file->write(reinterpret_cast<u8*>(&m_num_channels), sizeof(m_num_channels)); 97 98 m_file->write(reinterpret_cast<u8*>(&m_sample_rate), sizeof(m_sample_rate)); 99 100 u32 byte_rate = m_sample_rate * m_num_channels * (m_bits_per_sample / 8); 101 m_file->write(reinterpret_cast<u8*>(&byte_rate), sizeof(byte_rate)); 102 103 u16 block_align = m_num_channels * (m_bits_per_sample / 8); 104 m_file->write(reinterpret_cast<u8*>(&block_align), sizeof(block_align)); 105 106 m_file->write(reinterpret_cast<u8*>(&m_bits_per_sample), sizeof(m_bits_per_sample)); 107 108 // "data" 109 static u32 chunk_id = 0x61746164; 110 m_file->write(reinterpret_cast<u8*>(&chunk_id), sizeof(chunk_id)); 111 112 m_file->write(reinterpret_cast<u8*>(&m_data_sz), sizeof(m_data_sz)); 113} 114 115}