/* * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2016 Furrtek * * This file is part of PortaPack. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef __IO_WAVE_H #define __IO_WAVE_H #include "io_file.hpp" #include "file.hpp" #include "optional.hpp" #include struct fmt_pcm_t { constexpr fmt_pcm_t( const uint32_t sampling_rate) : nSamplesPerSec{sampling_rate}, nAvgBytesPerSec{nSamplesPerSec * 2} // nBlockAlign = 2 { } private: uint8_t ckID[4]{'f', 'm', 't', ' '}; uint32_t cksize{16}; uint16_t wFormatTag{0x0001}; uint16_t nChannels{1}; uint32_t nSamplesPerSec; uint32_t nAvgBytesPerSec; uint16_t nBlockAlign{2}; uint16_t wBitsPerSample{16}; }; struct data_t { constexpr data_t( const uint32_t size) : cksize{size} { } private: uint8_t ckID[4]{'d', 'a', 't', 'a'}; uint32_t cksize{0}; }; struct header_t { constexpr header_t( const uint32_t sampling_rate, const uint32_t data_chunk_size, const uint32_t info_chunk_size) : cksize{sizeof(header_t) + data_chunk_size + info_chunk_size - 8}, fmt{sampling_rate}, data{data_chunk_size} { } private: uint8_t riff_id[4]{'R', 'I', 'F', 'F'}; uint32_t cksize{0}; uint8_t wave_id[4]{'W', 'A', 'V', 'E'}; fmt_pcm_t fmt; data_t data; }; struct tags_t { constexpr tags_t( const std::string& title_str) { strcpy(title, title_str.c_str()); cksize = sizeof(tags_t) - 8; } private: uint8_t list_id[4]{'L', 'I', 'S', 'T'}; uint32_t cksize{0}; uint8_t info_id[4]{'I', 'N', 'F', 'O'}; uint8_t iart_id[4]{'I', 'A', 'R', 'T'}; uint32_t sckiart_size{12}; char artist[12]{"PortaPack\0\0"}; uint8_t inam_id[4]{'I', 'N', 'A', 'M'}; uint32_t sckinam_size{64}; char title[64]{0}; }; class WAVFileReader : public FileReader { public: WAVFileReader() = default; WAVFileReader(const WAVFileReader&) = delete; WAVFileReader& operator=(const WAVFileReader&) = delete; WAVFileReader(WAVFileReader&&) = delete; WAVFileReader& operator=(WAVFileReader&&) = delete; virtual ~WAVFileReader() = default; bool open(const std::filesystem::path& path); void data_seek(const uint64_t Offset); void rewind(); uint32_t ms_duration(); // int seek_mss(const uint16_t minutes, const uint8_t seconds, const uint32_t samples); uint16_t channels(); uint32_t sample_rate(); uint32_t data_size(); uint32_t sample_count(); uint16_t bits_per_sample(); std::string title(); private: struct fmt_pcm_t { uint8_t ckID[4]; // fmt uint32_t cksize; uint16_t wFormatTag; uint16_t nChannels; uint32_t nSamplesPerSec; uint32_t nAvgBytesPerSec; uint16_t nBlockAlign; uint16_t wBitsPerSample; }; struct data_t { uint8_t ckID[4]; // data uint32_t cksize; }; struct header_t { uint8_t riff_id[4]; // RIFF uint32_t cksize; uint8_t wave_id[4]; // WAVE fmt_pcm_t fmt; data_t data; }; header_t header{}; uint32_t data_start{}; uint32_t bytes_per_sample{}; uint32_t data_size_{0}; uint32_t sample_rate_{}; std::string title_string{}; std::filesystem::path last_path{}; }; class WAVFileWriter : public FileWriter { public: WAVFileWriter() = default; WAVFileWriter(const WAVFileWriter&) = delete; WAVFileWriter& operator=(const WAVFileWriter&) = delete; WAVFileWriter(WAVFileWriter&&) = delete; WAVFileWriter& operator=(WAVFileWriter&&) = delete; ~WAVFileWriter() { write_tags(); update_header(); } Optional create( const std::filesystem::path& filename, size_t sampling_rate, const std::string& title_set); private: uint32_t sampling_rate{0}; uint32_t info_chunk_size{0}; std::string title{}; Optional update_header(); Optional write_tags(); }; #endif