| 155 | } |
| 156 | |
| 157 | Result write(std::string filename, Format format=Format::PCM) { |
| 158 | if (channels == 0 || channels > 65535) return result = Result(Result::Code::WEIRD_CONFIG, "Invalid channel count"); |
| 159 | if (sampleRate <= 0 || sampleRate > 0xFFFFFFFFu) return result = Result(Result::Code::WEIRD_CONFIG, "Invalid sample rate"); |
| 160 | |
| 161 | std::ofstream file; |
| 162 | file.open(filename, std::ios::binary); |
| 163 | if (!file.is_open()) return result = Result(Result::Code::IO_ERROR, "Failed to open file: " + filename); |
| 164 | |
| 165 | int bytesPerSample; |
| 166 | switch (format) { |
| 167 | case Format::PCM: |
| 168 | bytesPerSample = 2; |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | // File size - 44 bytes is RIFF header, "fmt" block, and "data" block header |
| 173 | unsigned int dataLength = samples.size()*bytesPerSample; |
| 174 | unsigned int fileLength = 44 + dataLength; |
| 175 | |
| 176 | // RIFF chunk |
| 177 | write32(file, value_RIFF); |
| 178 | write32(file, fileLength - 8); // File length, excluding the RIFF header |
| 179 | write32(file, value_WAVE); |
| 180 | // "fmt " block |
| 181 | write32(file, value_fmt); |
| 182 | write32(file, 16); // block length |
| 183 | write16(file, (uint16_t)format); |
| 184 | write16(file, channels); |
| 185 | write32(file, sampleRate); |
| 186 | unsigned int expectedBytesPerSecond = sampleRate*channels*bytesPerSample; |
| 187 | write32(file, expectedBytesPerSecond); |
| 188 | write16(file, channels*bytesPerSample); // Bytes per frame |
| 189 | write16(file, bytesPerSample*8); // bist per sample |
| 190 | |
| 191 | // "data" block |
| 192 | write32(file, value_data); |
| 193 | write32(file, dataLength); |
| 194 | switch (format) { |
| 195 | case Format::PCM: |
| 196 | for (unsigned int i = 0; i < samples.size(); i++) { |
| 197 | double value = samples[i]*32768; |
| 198 | if (value > 32767) value = 32767; |
| 199 | if (value <= -32768) value = -32768; |
| 200 | if (value < 0) value += 65536; |
| 201 | write16(file, (uint16_t)value); |
| 202 | } |
| 203 | break; |
| 204 | } |
| 205 | return result = Result(Result::Code::OK); |
| 206 | } |
| 207 | |
| 208 | void makeMono() { |
| 209 | std::vector<double> newSamples(samples.size()/channels, 0); |
no test coverage detected