HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_wavwriter.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath> // delete me
4#include <string>
5#include <vector>
6
7#include "dependencies/choc/platform/choc_DisableAllWarnings.h"
8#include "dependencies/dr_libs/dr_wav.h"
9#include "dependencies/choc/platform/choc_ReenableAllWarnings.h"
10
13#include "hart_units.hpp"
14#include "hart_utils.hpp" // floatsEqual()
16
17namespace hart
18{
19
20/// @brief Helper class for writing audio buffers to wav files
21/// @details Intended for internal usem although can be used in the user tests as well
22/// @ingroup Utilities
23template <typename SampleType>
25{
26public:
27 static void writeBuffer (const AudioBuffer<SampleType>& buffer, const std::string& fileName, WavFormat wavFormat = WavFormat::pcm24)
28 {
29 // Sample rate must be supplied in buffer's metadata
30 hassert (buffer.hasSampleRate());
31 hassert (! floatsEqual (buffer.getSampleRateHz(), 0.0));
32
33 const size_t numFrames = buffer.getNumFrames();
34 const size_t numChannels = buffer.getNumChannels();
35
36 drwav drWavHandle;
37 drwav_data_format drWavFormat;
38 drWavFormat.container = drwav_container_riff;
39 drWavFormat.channels = static_cast<drwav_uint16> (numChannels);
40 drWavFormat.sampleRate = static_cast<drwav_uint32> (buffer.getSampleRateHz());
41
42 switch (wavFormat)
43 {
45 drWavFormat.format = DR_WAVE_FORMAT_PCM;
46 drWavFormat.bitsPerSample = 16;
47 break;
49 drWavFormat.format = DR_WAVE_FORMAT_PCM;
50 drWavFormat.bitsPerSample = 24;
51 break;
53 drWavFormat.format = DR_WAVE_FORMAT_PCM;
54 drWavFormat.bitsPerSample = 32;
55 break;
57 drWavFormat.format = DR_WAVE_FORMAT_IEEE_FLOAT;
58 drWavFormat.bitsPerSample = 32;
59 break;
60 }
61
62 if (! drwav_init_file_write (&drWavHandle, fileName.c_str(), &drWavFormat, nullptr))
63 HART_THROW_OR_RETURN_VOID (hart::IOError, "Failed to init WAV writer");
64
65 switch (wavFormat)
66 {
68 {
69 std::vector<float> pcmData (numFrames * numChannels);
70
71 for (size_t frame = 0; frame < numFrames; ++frame)
72 {
73 for (size_t channel = 0; channel < numChannels; ++channel)
74 pcmData[frame * numChannels + channel] = buffer[channel][frame];
75 }
76
77 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
78 break;
79 }
80
82 {
83 std::vector<int16_t> pcmData (numFrames * numChannels);
84 constexpr double scale = 32767.0;
85
86 for (size_t frame = 0; frame < numFrames; ++frame)
87 {
88 for (size_t channel = 0; channel < numChannels; ++channel)
89 {
90 const double sample = static_cast<double> (buffer[channel][frame]);
91 const int16_t pcmValue = static_cast<int16_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
92 pcmData[frame * numChannels + channel] = pcmValue;
93 }
94 }
95
96 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
97 break;
98 }
99
100 case WavFormat::pcm32:
101 {
102 std::vector<int32_t> pcmData (numFrames * numChannels);
103 constexpr double scale = 2147483647.0;
104
105 for (size_t frame = 0; frame < numFrames; ++frame)
106 {
107 for (size_t channel = 0; channel < numChannels; ++channel)
108 {
109 const double sample = static_cast<double> (buffer[channel][frame]);
110 const int32_t pcmValue = static_cast<int32_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
111 pcmData[frame * numChannels + channel] = pcmValue;
112 }
113 }
114
115 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
116 break;
117 }
118
119 case WavFormat::pcm24:
120 {
121 std::vector<uint8_t> pcmData (numFrames * numChannels * 3);
122 constexpr double scale = 8388607.0;
123
124 for (size_t frame = 0; frame < numFrames; ++frame)
125 {
126 for (size_t channel = 0; channel < numChannels; ++channel)
127 {
128 const double sample = static_cast<double> (buffer[channel][frame]);
129 const int32_t pcmValue = static_cast<int32_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
130 size_t idx = (frame * numChannels + channel) * 3;
131 pcmData[idx] = static_cast<uint8_t> (pcmValue & 0xff);
132 pcmData[idx + 1] = static_cast<uint8_t> ((pcmValue >> 8) & 0xff);
133 pcmData[idx + 2] = static_cast<uint8_t> ((pcmValue >> 16) & 0xff);
134 }
135 }
136
137 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
138 break;
139 }
140 }
141
142 drwav_uninit (&drWavHandle);
143 }
144};
145
146} // namespace hart
Container for audio data.
Thrown when some I/O operation fails.
Helper class for writing audio buffers to wav files.
static void writeBuffer(const AudioBuffer< SampleType > &buffer, const std::string &fileName, WavFormat wavFormat=WavFormat::pcm24)
#define HART_THROW_OR_RETURN_VOID(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns otherwise.
#define hassert(condition)
Triggers a HartAssertException if the condition is false
NumericType clamp(const NumericType &value, const NumericType &low, const NumericType &high)
std::clamp() replacement for C++11
WavFormat
Audio data storage format for the wav files.