nngn
Loading...
Searching...
No Matches
wav.h
Go to the documentation of this file.
1#ifndef NNGN_AUDIO_WAV_H
2#define NNGN_AUDIO_WAV_H
3
4#include <bit>
5#include <cassert>
6#include <climits>
7#include <cstring>
8#include <span>
9#include <string_view>
10
11#include "utils/def.h"
12#include "utils/literals.h"
13#include "utils/utils.h"
14
15namespace nngn {
16
17using namespace std::string_view_literals;
18using namespace nngn::literals;
19
21class WAV {
22 static_assert(std::endian::native == std::endian::little, "TODO");
23public:
24 static constexpr std::size_t HEADER_SIZE = 44;
26 WAV(void) = default;
27 constexpr explicit WAV(std::span<std::byte> buffer);
28 constexpr u32 fmt_size(void) const;
29 constexpr u16 format(void) const;
30 constexpr u16 channels(void) const;
31 constexpr u32 rate(void) const;
32 constexpr u16 bits_per_sample(void) const;
33 constexpr std::size_t n_samples(void) const;
34 constexpr void set_size(u32 s) const;
35 constexpr void set_channels(u16 c) const;
36 constexpr void set_rate(u32 r) const;
37 constexpr void fill(void) const;
38 constexpr std::span<std::byte> data(void) const;
39 bool check(void) const;
40private:
41 enum class offset : std::size_t {
42 RIFF_SEG = 0,
43 SEG_SIZE = 4,
44 WAVE_SEG = 8,
45 FMT_SEG = 12,
46 FMT_SIZE = 16,
47 FORMAT = 20,
48 CHANNELS = 22,
49 RATE = 24,
50 BYTES_PER_SEC = 28,
51 BLOCK_ALIGN = 32,
52 BITS_PER_SAMPLE = 34,
53 DATA_SEG = 36,
54 DATA_SIZE = 40,
56 };
57 struct segment {
58 static constexpr auto RIFF = "RIFF"sv;
59 static constexpr auto WAVE = "WAVE"sv;
60 static constexpr auto FMT = "fmt "sv;
61 static constexpr auto DATA = "data"sv;
62 };
63 constexpr std::span<std::byte> subspan(offset o, std::size_t n) const;
64 template<typename T> constexpr T read(offset o) const;
65 template<typename T> constexpr void write(offset o, const T &x) const;
66 constexpr std::size_t size(void) const;
67 std::span<std::byte> b = {};
68};
69
70inline constexpr WAV::WAV(std::span<std::byte> buffer) : b{buffer} {
71 assert(WAV::HEADER_SIZE <= this->b.size());
72};
73
74inline constexpr std::span<std::byte> WAV::subspan(
75 offset o, std::size_t n
76) const {
77 const auto oz = static_cast<std::size_t>(o);
78 assert(oz + n <= this->b.size());
79 return this->b.subspan(oz, n);
80}
81
82template<typename T>
83constexpr T WAV::read(offset o) const {
84 T ret = {};
85 std::memcpy(&ret, this->subspan(o, sizeof(ret)).data(), sizeof(ret));
86 return ret;
87}
88
89template<typename T>
90constexpr void WAV::write(offset o, const T &x) const {
91 if constexpr(std::ranges::range<T>) {
92 auto s = this->subspan(o, x.size());
93 std::memcpy(s.data(), x.data(), x.size());
94 } else {
95 auto s = this->subspan(o, sizeof(T));
96 std::memcpy(s.data(), &x, sizeof(T));
97 }
98}
99
100inline constexpr u32 WAV::fmt_size(void) const {
101 return this->read<u32>(offset::FMT_SIZE);
102}
103
104inline constexpr u16 WAV::format(void) const {
105 return this->read<u16>(offset::FORMAT);
106}
107
108inline constexpr u16 WAV::channels(void) const {
109 return this->read<u16>(offset::CHANNELS);
110}
111
112inline constexpr u32 WAV::rate(void) const {
113 return this->read<u32>(offset::RATE);
114}
115
116inline constexpr u16 WAV::bits_per_sample(void) const {
117 return this->read<u16>(offset::BITS_PER_SAMPLE);
118}
119
120inline constexpr std::size_t WAV::n_samples(void) const {
121 return this->size() * CHAR_BIT / this->bits_per_sample();
122}
123
124inline constexpr std::size_t WAV::size(void) const {
125 return this->read<u32>(offset::DATA_SIZE);
126}
127
128inline constexpr std::span<std::byte> WAV::data(void) const {
129 assert(this->size() == this->b.size() - WAV::HEADER_SIZE);
130 return this->subspan(offset::DATA, this->size());
131}
132
133inline constexpr void WAV::set_size(u32 s) const {
134 this->write(offset::SEG_SIZE, s + 40);
135 this->write(offset::DATA_SIZE, s);
136}
137
138inline constexpr void WAV::set_channels(u16 c) const {
139 this->write(offset::CHANNELS, c);
140}
141
142inline constexpr void WAV::set_rate(u32 r) const {
143 this->write(offset::RATE, r);
144}
145
146inline constexpr void WAV::fill(void) const {
147 constexpr u16 bits_per_sample = 16;
148 constexpr std::size_t bytes_per_sample = bits_per_sample / 8;
149 const auto r = this->rate();
150 const auto c = this->channels();
154 this->write(offset::FMT_SIZE, 16_u32);
155 this->write(offset::FORMAT, 1_u16);
156 this->write(
158 static_cast<u32>(r * bytes_per_sample * c));
159 this->write(offset::BLOCK_ALIGN, static_cast<u16>(bytes_per_sample * c));
160 this->write(offset::BITS_PER_SAMPLE, bits_per_sample);
162}
163
164}
165
166#endif
A non-owning wrapper for a byte buffer containing a WAV file.
Definition: wav.h:21
static constexpr std::size_t HEADER_SIZE
Definition: wav.h:24
constexpr void set_rate(u32 r) const
constexpr u16 bits_per_sample(void) const
WAV(void)=default
Constructs an empty object, must be initialized before it is used.
constexpr void write(offset o, const T &x) const
constexpr void set_size(u32 s) const
offset
Definition: wav.h:41
constexpr std::span< std::byte > data(void) const
constexpr u32 fmt_size(void) const
std::span< std::byte > b
Definition: wav.h:67
constexpr u16 channels(void) const
constexpr WAV(std::span< std::byte > buffer)
constexpr void fill(void) const
constexpr u16 format(void) const
constexpr T read(offset o) const
constexpr u32 rate(void) const
bool check(void) const
constexpr std::span< std::byte > subspan(offset o, std::size_t n) const
constexpr std::size_t size(void) const
constexpr std::size_t n_samples(void) const
constexpr void set_channels(u16 c) const
r
Definition: gamma.lua:7
c
Definition: gamma.lua:11
assert
Definition: debug.lua:3
n
Definition: dump_lights.lua:5
std::chrono::seconds s
Definition: timing.cpp:6
#define T(f0, f1, f2)
Definition: literals.h:9
Definition: audio.cpp:7
std::uint32_t u32
Definition: def.h:14
std::uint16_t u16
Definition: def.h:13
static constexpr auto DATA
Definition: wav.h:61
static constexpr auto RIFF
Definition: wav.h:58
static constexpr auto WAVE
Definition: wav.h:59
static constexpr auto FMT
Definition: wav.h:60