1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "libvideostitch/audioWav.hpp"
#include <vector>
#include <cmath>
namespace VideoStitch {
namespace Audio {
///////////////////////////////////////////////////////////
//
// AudioObject::WavWriter
//
///////////////////////////////////////////////////////////
//
// Wav file writer
//
//
WavWriter::WavWriter(const char *fileName, const ChannelLayout layout, const double sampleRate)
: AudioObject("wavwriter", AudioFunction::SINK, getNbChannelsFromChannelLayout(layout), 0, sampleRate),
_fileSize(0),
_fileName(fileName) {
_f.open(fileName, std::ios::out);
assert(_f.is_open());
_writeHeader();
}
void WavWriter::updateFileSize() {
// Write file size field
_f.seekp(4); // Bytes [ 4 .. 7 ]
_f.write((char *)&_fileSize, 4);
// Write data size field
_f.seekp(40); // Bytes [ 40 .. 43 ]
std::uint32_t dataSize = _fileSize - 44;
_f.write((char *)&dataSize, 4);
_f.seekp(std::ios_base::end);
}
void WavWriter::close() {
updateFileSize();
// Close file
_f.close();
}
void WavWriter::step(const AudioBlock &buf) { step(const_cast<AudioBlock &>(buf)); }
void WavWriter::step(AudioBlock &buf) {
size_t nSamples = buf.numSamples();
if (nSamples > 0) {
int nChannels = getNbChannelsFromChannelLayout(buf.getLayout());
float *interleaved = new float[(int)nSamples * nChannels];
for (size_t s = 0; s < nSamples; ++s) {
int c = 0;
for (const auto &track : buf) {
interleaved[s * nChannels + c] = static_cast<float>(track[s]);
c++;
}
}
size_t bufferSize = nSamples * nChannels * sizeof(float);
_fileSize += static_cast<uint32_t>(bufferSize);
_f.write((const char *)interleaved, bufferSize);
delete[] interleaved;
}
}
// To be tested
void WavWriter::step(AudioTrack &track) {
for (auto sample : track) {
float value = (float)sample;
_f.write((char *)&value, 4);
_fileSize += 4;
}
// std::cout << _fileName << " _fileSize " << _fileSize << std::endl;
}
void WavWriter::step(const audioSample_t *data, const size_t size) {
for (size_t s = 0; s < size; s++) {
float value = (float)data[s];
_f.write((char *)&value, sizeof(float));
_fileSize += 4;
}
}
void WavWriter::append(const audioSample_t *data, const size_t size) {
if (!_f.is_open()) _f.open(_fileName, std::ios::in | std::ios::out);
_f.seekp(std::ios_base::end);
step(data, size);
close();
}
void WavWriter::_writeHeader() {
uint32_t u32;
uint16_t u16;
_f.write("RIFF", 4);
u32 = 0;
_f.write((char *)&u32, 4); // Will have to write the file size here on closing
_f.write("WAVEfmt ", 8);
u32 = 16; // Format block length
_f.write((char *)&u32, 4);
u16 = 3; // Float sample format
_f.write((char *)&u16, 2);
u16 = (std::uint16_t)getInputs(); // Channels
_f.write((char *)&u16, 2);
u32 = (std::uint32_t)lround(getSampleRate()); // Samples per second (Fs)
_f.write((char *)&u32, 4);
// u32 *= (std::uint32_t) ( getInputs() * 4 ); // Bytes per second [ Fs * nChans * ( bits_per_samp / 8 ) ]
u32 = 0; // FIXME on windows this field is not well written
_f.write((char *)&u32, 4);
u16 = ((std::uint16_t)getInputs() * 4); // Block align [ nChannels * sizeof (float) ]
_f.write((char *)&u16, 2);
u16 = 32; // Bits per sample
_f.write((char *)&u16, 2);
_f.write("data", 4);
u32 = 0; // Will have to write the data size here on closing
_f.write((char *)&u32, 4);
_fileSize = 44;
}
} // namespace Audio
} // namespace VideoStitch