HART  0.1.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 "dr_wav.h"
8
11#include "hart_units.hpp"
13
14namespace hart
15{
16
17template <typename SampleType>
19{
20public:
21 static void writeBuffer (const AudioBuffer<SampleType>& buffer, const std::string& fileName, double sampleRateHz, WavFormat wavFormat = WavFormat::pcm24)
22 {
23 const size_t numFrames = buffer.getNumFrames();
24 const size_t numChannels = buffer.getNumChannels();
25
26 drwav drWavHandle;
27 drwav_data_format drWavFormat;
28 drWavFormat.container = drwav_container_riff;
29 drWavFormat.channels = static_cast<drwav_uint16> (numChannels);
30 drWavFormat.sampleRate = static_cast<drwav_uint32> (sampleRateHz);
31
32 switch (wavFormat)
33 {
35 drWavFormat.format = DR_WAVE_FORMAT_PCM;
36 drWavFormat.bitsPerSample = 16;
37 break;
39 drWavFormat.format = DR_WAVE_FORMAT_PCM;
40 drWavFormat.bitsPerSample = 24;
41 break;
43 drWavFormat.format = DR_WAVE_FORMAT_PCM;
44 drWavFormat.bitsPerSample = 32;
45 break;
47 drWavFormat.format = DR_WAVE_FORMAT_IEEE_FLOAT;
48 drWavFormat.bitsPerSample = 32;
49 break;
50 }
51
52 if (! drwav_init_file_write (&drWavHandle, fileName.c_str(), &drWavFormat, nullptr))
53 HART_THROW_OR_RETURN_VOID (hart::IOError, "Failed to init WAV writer");
54
55 switch (wavFormat)
56 {
58 {
59 std::vector<float> pcmData (numFrames * numChannels);
60
61 for (size_t frame = 0; frame < numFrames; ++frame)
62 {
63 for (size_t channel = 0; channel < numChannels; ++channel)
64 pcmData[frame * numChannels + channel] = buffer[channel][frame];
65 }
66
67 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
68 break;
69 }
70
72 {
73 std::vector<int16_t> pcmData (numFrames * numChannels);
74 constexpr double scale = 32767.0;
75
76 for (size_t frame = 0; frame < numFrames; ++frame)
77 {
78 for (size_t channel = 0; channel < numChannels; ++channel)
79 {
80 const double sample = static_cast<double> (buffer[channel][frame]);
81 const int16_t pcmValue = static_cast<int16_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
82 pcmData[frame * numChannels + channel] = pcmValue;
83 }
84 }
85
86 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
87 break;
88 }
89
91 {
92 std::vector<int32_t> pcmData (numFrames * numChannels);
93 constexpr double scale = 2147483647.0;
94
95 for (size_t frame = 0; frame < numFrames; ++frame)
96 {
97 for (size_t channel = 0; channel < numChannels; ++channel)
98 {
99 const double sample = static_cast<double> (buffer[channel][frame]);
100 const int32_t pcmValue = static_cast<int32_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
101 pcmData[frame * numChannels + channel] = pcmValue;
102 }
103 }
104
105 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
106 break;
107 }
108
109 case WavFormat::pcm24:
110 {
111 std::vector<uint8_t> pcmData (numFrames * numChannels * 3);
112 constexpr double scale = 8388607.0;
113
114 for (size_t frame = 0; frame < numFrames; ++frame)
115 {
116 for (size_t channel = 0; channel < numChannels; ++channel)
117 {
118 const double sample = static_cast<double> (buffer[channel][frame]);
119 const int32_t pcmValue = static_cast<int32_t> (std::round (hart::clamp (scale * sample, -scale, scale)));
120 size_t idx = (frame * numChannels + channel) * 3;
121 pcmData[idx] = static_cast<uint8_t> (pcmValue & 0xff);
122 pcmData[idx + 1] = static_cast<uint8_t> ((pcmValue >> 8) & 0xff);
123 pcmData[idx + 2] = static_cast<uint8_t> ((pcmValue >> 16) & 0xff);
124 }
125 }
126
127 drwav_write_pcm_frames (&drWavHandle, numFrames, pcmData.data());
128 break;
129 }
130 }
131
132 drwav_uninit (&drWavHandle);
133 }
134};
135
136} // namespace hart
static void writeBuffer(const AudioBuffer< SampleType > &buffer, const std::string &fileName, double sampleRateHz, WavFormat wavFormat=WavFormat::pcm24)
NumericType clamp(const NumericType &value, const NumericType &low, const NumericType &high)
std::clamp() replacement for C++11
#define HART_THROW_OR_RETURN_VOID(ExceptionType, message)