Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "wavencoder.h"
24 :
25 : #include <limits>
26 :
27 : #include "../dsp/audiomathutils.h"
28 :
29 : #include "global/io/iodevice.h"
30 : #include "global/types/bytearray.h"
31 :
32 : #include "log.h"
33 :
34 : namespace muse::audio::encode {
35 : namespace {
36 : template<typename T>
37 0 : void writeTagData(io::IODevice& outDev, const T value, size_t offset = 0)
38 : {
39 0 : if (offset != 0) {
40 0 : outDev.seek(offset);
41 : }
42 :
43 : // little endian
44 0 : outDev.write(reinterpret_cast<const std::uint8_t*>(&value), sizeof(T));
45 0 : }
46 :
47 : struct WavHeader {
48 : uint32_t chunkSize = 0;
49 : uint16_t audioChannelsNumber = 0;
50 : uint16_t bitsPerSample = 0;
51 : uint32_t samplesPerChannel = 0;
52 : uint16_t code = 0;
53 : uint32_t sampleRate = 0;
54 :
55 0 : void write(io::IODevice& outDev)
56 : {
57 0 : const uint32_t bytesPerSample = bitsPerSample / 8;
58 0 : const uint32_t sampleDataLength = audioChannelsNumber * samplesPerChannel * bytesPerSample;
59 0 : const uint32_t headerLength = 20 + chunkSize + 8;
60 0 : const uint32_t file_length = headerLength + sampleDataLength;
61 0 : const uint32_t overallSize = file_length - 8;
62 0 : const uint32_t bytesPerFrame = audioChannelsNumber * bytesPerSample;
63 0 : const uint32_t bytesPerSec = audioChannelsNumber * sampleRate * bytesPerSample;
64 :
65 0 : outDev.write(ByteArray::fromRawData("RIFF", 4)); // chunk ID
66 :
67 0 : writeTagData<uint32_t>(outDev, overallSize);
68 0 : outDev.write(ByteArray::fromRawData("WAVE", 4)); // WAVEID
69 0 : outDev.write(ByteArray::fromRawData("fmt ", 4)); // chunk ID
70 :
71 0 : writeTagData<uint32_t>(outDev, chunkSize);
72 0 : writeTagData<uint16_t>(outDev, code);
73 0 : writeTagData<uint16_t>(outDev, audioChannelsNumber);
74 0 : writeTagData<uint32_t>(outDev, sampleRate);
75 0 : writeTagData<uint32_t>(outDev, bytesPerSec);
76 0 : writeTagData<uint16_t>(outDev, bytesPerFrame);
77 0 : writeTagData<uint16_t>(outDev, bitsPerSample);
78 :
79 0 : uint16_t ext = 0;
80 0 : if (chunkSize > 16) {
81 0 : writeTagData<uint16_t>(outDev, ext); // cbSize (extension size)
82 : }
83 0 : outDev.write(ByteArray::fromRawData("data", 4)); // chunk ID
84 :
85 0 : writeTagData<uint32_t>(outDev, sampleDataLength);
86 0 : }
87 : };
88 : }
89 :
90 0 : WavEncoder::WavEncoder(const SoundTrackFormat& format, io::IODevice& dstDevice)
91 0 : : AbstractAudioEncoder(format), m_dstDevice{&dstDevice}
92 : {
93 0 : DO_ASSERT(m_dstDevice);
94 0 : }
95 :
96 0 : bool WavEncoder::begin(const samples_t)
97 : {
98 0 : m_headerWritten = false;
99 0 : m_pcmStartPos = 0;
100 0 : return true;
101 : }
102 :
103 0 : bool WavEncoder::writePlaceholderHeader()
104 : {
105 0 : WavHeader header;
106 0 : header.chunkSize = 18; // 18 is 2 bytes more to include cbsize field / extension size
107 :
108 0 : switch (m_format.sampleFormat) {
109 0 : case AudioSampleFormat::Int16:
110 0 : header.bitsPerSample = 16;
111 0 : header.code = 1; // PCM
112 0 : break;
113 0 : case AudioSampleFormat::Int24:
114 0 : header.bitsPerSample = 24;
115 0 : header.code = 1; // PCM
116 0 : break;
117 0 : case AudioSampleFormat::Float32:
118 0 : header.bitsPerSample = 32;
119 0 : header.code = 3; // IEEE_FLOAT
120 0 : break;
121 0 : case AudioSampleFormat::Undefined:
122 : default:
123 0 : return false;
124 : }
125 :
126 0 : header.audioChannelsNumber = m_format.outputSpec.audioChannelCount;
127 0 : header.sampleRate = m_format.outputSpec.sampleRate;
128 0 : header.samplesPerChannel = 0;
129 :
130 0 : header.write(*m_dstDevice);
131 0 : return true;
132 : }
133 :
134 0 : void WavEncoder::patchHeaderSizes()
135 : {
136 0 : const size_t endPos = m_dstDevice->pos();
137 0 : if (endPos < m_pcmStartPos || endPos < 8) {
138 0 : return;
139 : }
140 :
141 0 : const uint64_t dataBytes = endPos - m_pcmStartPos;
142 0 : if (dataBytes > std::numeric_limits<uint32_t>::max()) {
143 0 : LOGE() << "WAV export: file size exceeds 32-bit chunk limits";
144 0 : return;
145 : }
146 :
147 0 : const uint32_t dataSize = static_cast<uint32_t>(dataBytes);
148 0 : const uint32_t riffChunkSize = static_cast<uint32_t>(endPos - 8);
149 :
150 0 : writeTagData<uint32_t>(*m_dstDevice, riffChunkSize, 4); // RIFF chunk size at offset 4
151 0 : writeTagData<uint32_t>(*m_dstDevice, dataSize, 42); // data chunk size at offset 42 (with 18-byte fmt + cbSize)
152 :
153 0 : m_dstDevice->seek(endPos);
154 : }
155 :
156 0 : size_t WavEncoder::encode(const samples_t samplesPerChannel, const float* input)
157 : {
158 0 : if (!m_headerWritten) {
159 0 : if (!writePlaceholderHeader()) {
160 0 : return 0;
161 : }
162 0 : m_pcmStartPos = m_dstDevice->pos();
163 0 : m_headerWritten = true;
164 : }
165 :
166 0 : const int channels = m_format.outputSpec.audioChannelCount;
167 :
168 0 : if (m_format.sampleFormat == AudioSampleFormat::Float32) {
169 0 : for (samples_t sampleIdx = 0; sampleIdx < samplesPerChannel; ++sampleIdx) {
170 0 : for (audioch_t audioChNum = 0; audioChNum < channels; ++audioChNum) {
171 0 : const int idx = static_cast<int>(sampleIdx) * channels + audioChNum;
172 0 : if (m_dstDevice->write(reinterpret_cast<const std::uint8_t*>(input + idx), 4) != 4) {
173 0 : return 0;
174 : }
175 : }
176 : }
177 : } else {
178 0 : int bitsPerSample = 0;
179 0 : switch (m_format.sampleFormat) {
180 0 : case AudioSampleFormat::Int16:
181 0 : bitsPerSample = 16;
182 0 : break;
183 0 : case AudioSampleFormat::Int24:
184 0 : bitsPerSample = 24;
185 0 : break;
186 0 : default:
187 0 : return 0;
188 : }
189 :
190 0 : const int bytesToWrite = bitsPerSample / 8;
191 :
192 0 : for (samples_t sampleIdx = 0; sampleIdx < samplesPerChannel; ++sampleIdx) {
193 0 : for (audioch_t audioChNum = 0; audioChNum < channels; ++audioChNum) {
194 0 : const int idx = static_cast<int>(sampleIdx) * channels + audioChNum;
195 :
196 0 : const int32_t sampleInt = dsp::convertFloatSamples<int32_t>(input[idx], bitsPerSample);
197 :
198 0 : m_dstDevice->write(reinterpret_cast<const std::uint8_t*>(&sampleInt), bytesToWrite);
199 : }
200 : }
201 : }
202 :
203 0 : return static_cast<size_t>(samplesPerChannel) * static_cast<size_t>(channels);
204 : }
205 :
206 0 : size_t WavEncoder::end()
207 : {
208 0 : if (m_headerWritten) {
209 0 : patchHeaderSizes();
210 : }
211 :
212 0 : return 0;
213 : }
214 : }
|