|
| 1 | +// WavDepthReduce.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 |
| 2 | +// |
| 3 | + |
| 4 | +#include "stdafx.h" |
| 5 | + |
| 6 | +int getFileSize(wchar_t* fileName, DWORD* sizeLow, DWORD* sizeHigh) |
| 7 | +{ |
| 8 | + HANDLE h; |
| 9 | + DWORD dwSizeHigh; |
| 10 | + DWORD dwSizeLow; |
| 11 | + DWORD dwError; |
| 12 | + |
| 13 | + if (sizeLow == 0 || sizeHigh == 0) return 0; |
| 14 | + *sizeLow = *sizeHigh = 0; |
| 15 | + h = CreateFileW(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
| 16 | + if (h == INVALID_HANDLE_VALUE) return 0; |
| 17 | + dwSizeLow = GetFileSize(h, &dwSizeHigh); |
| 18 | + dwError = GetLastError(); |
| 19 | + CloseHandle(h); |
| 20 | + if (dwSizeLow == 0xffffffff && dwError != NO_ERROR) return 0; |
| 21 | + *sizeLow = dwSizeLow; |
| 22 | + *sizeHigh = dwSizeHigh; |
| 23 | + return 1; |
| 24 | +} |
| 25 | + |
| 26 | +unsigned int searchFmtDataChunk(wchar_t* fileName, WAVEFORMATEX* wf, DWORD* offset, DWORD* size) |
| 27 | +{ |
| 28 | + HANDLE fileHandle; |
| 29 | + fileHandle = CreateFileW(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
| 30 | + if (fileHandle == INVALID_HANDLE_VALUE) |
| 31 | + { |
| 32 | + return 0; |
| 33 | + } |
| 34 | + |
| 35 | + DWORD header[2]; |
| 36 | + DWORD readSize; |
| 37 | + WORD wav[8]; |
| 38 | + DWORD riffSize, pos = 0; |
| 39 | + DWORD dataOffset, dataSize; |
| 40 | + ::ReadFile(fileHandle, header, 8, &readSize, NULL); |
| 41 | + bool fmtFound = false, dataFound = false; |
| 42 | + |
| 43 | + if (readSize != 8) |
| 44 | + { |
| 45 | + CloseHandle(fileHandle); |
| 46 | + return 0; |
| 47 | + } |
| 48 | + |
| 49 | + if (header[0] != 0X46464952) |
| 50 | + { |
| 51 | + // not "RIFF" |
| 52 | + CloseHandle(fileHandle); |
| 53 | + return 0; |
| 54 | + } |
| 55 | + riffSize = header[1]; |
| 56 | + |
| 57 | + ::ReadFile(fileHandle, header, 4, &readSize, NULL); |
| 58 | + if (readSize != 4) |
| 59 | + { |
| 60 | + CloseHandle(fileHandle); |
| 61 | + return 0; |
| 62 | + } |
| 63 | + if (header[0] != 0x45564157) |
| 64 | + { |
| 65 | + // not "WAVE" |
| 66 | + CloseHandle(fileHandle); |
| 67 | + return 0; |
| 68 | + } |
| 69 | + pos += 4; |
| 70 | + |
| 71 | + while (pos < riffSize) |
| 72 | + { |
| 73 | + ::ReadFile(fileHandle, header, 8, &readSize, NULL); |
| 74 | + if (readSize != 8) |
| 75 | + { |
| 76 | + break; |
| 77 | + } |
| 78 | + pos += 8; |
| 79 | + |
| 80 | + if (header[0] == 0X20746d66) |
| 81 | + { |
| 82 | + // "fmt " |
| 83 | + if (header[1] >= 16) |
| 84 | + { |
| 85 | + ::ReadFile(fileHandle, wav, 16, &readSize, NULL); |
| 86 | + if (readSize != 16) |
| 87 | + { |
| 88 | + break; |
| 89 | + } |
| 90 | + fmtFound = true; |
| 91 | + if (header[1] > 16) |
| 92 | + { |
| 93 | + ::SetFilePointer(fileHandle, header[1] - 16, 0, FILE_CURRENT); |
| 94 | + } |
| 95 | + pos += header[1]; |
| 96 | + } |
| 97 | + else |
| 98 | + { |
| 99 | + ::SetFilePointer(fileHandle, header[1], 0, FILE_CURRENT); |
| 100 | + pos += header[1]; |
| 101 | + } |
| 102 | + } |
| 103 | + else if (header[0] == 0X61746164) |
| 104 | + { |
| 105 | + // "data" |
| 106 | + dataFound = true; |
| 107 | + dataOffset = ::SetFilePointer(fileHandle, 0, 0, FILE_CURRENT); |
| 108 | + dataSize = header[1]; |
| 109 | + ::SetFilePointer(fileHandle, header[1], 0, FILE_CURRENT); |
| 110 | + pos += header[1]; |
| 111 | + } |
| 112 | + else |
| 113 | + { |
| 114 | + ::SetFilePointer(fileHandle, header[1], 0, FILE_CURRENT); |
| 115 | + pos += header[1]; |
| 116 | + } |
| 117 | + if (GetLastError() != NO_ERROR) |
| 118 | + { |
| 119 | + break; |
| 120 | + } |
| 121 | + } |
| 122 | + CloseHandle(fileHandle); |
| 123 | + |
| 124 | + if (dataFound && fmtFound) |
| 125 | + { |
| 126 | + *offset = dataOffset; |
| 127 | + *size = dataSize; |
| 128 | + wf->wFormatTag = wav[0]; // 1:LPCM 3:IEEE float |
| 129 | + wf->nChannels = wav[1]; // 1:Mono 2:Stereo |
| 130 | + wf->nSamplesPerSec = *(DWORD* )(wav+ 2); // 44100, 48000, 176400, 19200, 352800, 384000... |
| 131 | + wf->nAvgBytesPerSec = *(DWORD* )(wav + 4); |
| 132 | + wf->nBlockAlign = wav[6]; // 4@16bit/2ch, 6@24bit/2ch, 8@32bit/2ch |
| 133 | + wf->wBitsPerSample = wav[7]; // 16bit, 24bit, 32bit |
| 134 | + wf->cbSize = 0; |
| 135 | + return 1; |
| 136 | + } |
| 137 | + return 0; |
| 138 | +} |
| 139 | + |
| 140 | +void* readWavFile(wchar_t* fileName) |
| 141 | +{ |
| 142 | + HANDLE fileHandle; |
| 143 | + DWORD offset, size, readSize; |
| 144 | + void* data; |
| 145 | + WAVEFORMATEX wf; |
| 146 | + |
| 147 | + if (!searchFmtDataChunk(fileName, &wf, &offset, &size)) |
| 148 | + { |
| 149 | + return 0; |
| 150 | + } |
| 151 | + |
| 152 | + fileHandle = CreateFileW(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
| 153 | + if (fileHandle == INVALID_HANDLE_VALUE) |
| 154 | + { |
| 155 | + return 0; |
| 156 | + } |
| 157 | + |
| 158 | + data = (void*) ::GlobalAlloc(GPTR, ((size + 15) / 16) * 16); |
| 159 | + |
| 160 | + ::SetFilePointer(fileHandle, offset, 0, FILE_CURRENT); |
| 161 | + ::ReadFile(fileHandle, data, size, &readSize, NULL); |
| 162 | + ::CloseHandle(fileHandle); |
| 163 | + |
| 164 | + return data; |
| 165 | +} |
| 166 | + |
| 167 | +int writeWAV_header(HANDLE fileHandle, int ch, int freq, int depth, unsigned long dataSize) |
| 168 | +{ |
| 169 | + if (fileHandle == 0) return 0; |
| 170 | + if (ch != 1 && ch != 2) return 0; |
| 171 | + if (depth != 16 && depth != 24 && depth != 32) return 0; |
| 172 | + |
| 173 | + WAVEFORMATEX wf; |
| 174 | + wf.wFormatTag = 0x01; // 1:LPCM |
| 175 | + wf.nChannels = ch; |
| 176 | + wf.nSamplesPerSec = freq; |
| 177 | + wf.nAvgBytesPerSec = freq * ((depth * ch) / 8); |
| 178 | + wf.nBlockAlign = (depth * ch) / 8; // 4bytes (16bit, 2ch) per sample |
| 179 | + wf.wBitsPerSample = depth; |
| 180 | + wf.cbSize = 0; |
| 181 | + |
| 182 | + DWORD writtenSize = 0; |
| 183 | + WriteFile(fileHandle, "RIFF", 4, &writtenSize, NULL); |
| 184 | + DWORD size = (dataSize + 44) - 8; |
| 185 | + WriteFile(fileHandle, &size, 4, &writtenSize, NULL); |
| 186 | + WriteFile(fileHandle, "WAVE", 4, &writtenSize, NULL); |
| 187 | + WriteFile(fileHandle, "fmt ", 4, &writtenSize, NULL); |
| 188 | + size = 16; |
| 189 | + WriteFile(fileHandle, &size, 4, &writtenSize, NULL); |
| 190 | + WriteFile(fileHandle, &wf, size, &writtenSize, NULL); |
| 191 | + WriteFile(fileHandle, "data", 4, &writtenSize, NULL); |
| 192 | + size = (DWORD)dataSize; |
| 193 | + WriteFile(fileHandle, &size, 4, &writtenSize, NULL); |
| 194 | + |
| 195 | + return 0; |
| 196 | +} |
| 197 | + |
| 198 | +// X次 ノイズシェーパー |
| 199 | +void noiseShaper(wchar_t* destFileName, void* data, int sample, WAVEFORMATEX* wf, int x) |
| 200 | +{ |
| 201 | + HANDLE fileHandle = CreateFileW(destFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS /*CREATE_NEW*/, FILE_ATTRIBUTE_NORMAL, NULL); |
| 202 | + writeWAV_header(fileHandle, 2, wf->nSamplesPerSec, 16, sample * 2 * 2); |
| 203 | + |
| 204 | + short* data2 = (short*)::GlobalAlloc(GPTR, sample * 2 * 2); |
| 205 | + |
| 206 | + BYTE* p = (BYTE*)data; |
| 207 | + int left, right, add = 1 << 7; |
| 208 | + DWORD writtenSize; |
| 209 | + |
| 210 | + int lastRight = 0; |
| 211 | + int lastLeft = 0; |
| 212 | + int outRight; |
| 213 | + int outLeft; |
| 214 | + long long sigmaLeft[32]; |
| 215 | + long long sigmaRight[32]; |
| 216 | + |
| 217 | + short n = -1; |
| 218 | + |
| 219 | + for (int i = 0; i < 32; ++i) |
| 220 | + { |
| 221 | + sigmaLeft[i] = sigmaRight[i] = 0; |
| 222 | + } |
| 223 | + |
| 224 | + for (int i = 0; i < sample; ++i) |
| 225 | + { |
| 226 | + unsigned int tmp; |
| 227 | + tmp = (p[2] << 16) | (p[1] << 8) | p[0]; |
| 228 | + if (tmp > 0x00800000) |
| 229 | + { |
| 230 | + left = (0x01000000 - tmp) * -1; |
| 231 | + } |
| 232 | + else left = (int)tmp; |
| 233 | + |
| 234 | + tmp = (p[5] << 16) | (p[4] << 8) | p[3]; |
| 235 | + if (tmp > 0x00800000) |
| 236 | + { |
| 237 | + right = (0x01000000 - tmp) * -1; |
| 238 | + } |
| 239 | + else right = (int)tmp; |
| 240 | + |
| 241 | + sigmaLeft[0] += left - lastLeft; |
| 242 | + sigmaRight[0] += right - lastRight; |
| 243 | + for (int j = 1; j < x; ++j) |
| 244 | + { |
| 245 | + sigmaLeft[j] += sigmaLeft[j - 1] - lastLeft; |
| 246 | + sigmaRight[j] += sigmaRight[j - 1] - lastRight; |
| 247 | + } |
| 248 | + |
| 249 | + if (sigmaLeft[x - 1] >= 0) |
| 250 | + { |
| 251 | + outLeft = (sigmaLeft[x - 1] + add) >> 8; |
| 252 | + lastLeft = outLeft << 8; |
| 253 | + } |
| 254 | + else |
| 255 | + { |
| 256 | + outLeft = (sigmaLeft[x - 1] * -1 + add) >> 8; |
| 257 | + lastLeft = outLeft << 8; |
| 258 | + outLeft *= -1; |
| 259 | + lastLeft *= -1; |
| 260 | + } |
| 261 | + |
| 262 | + ///// right |
| 263 | + if (sigmaRight[x - 1] >= 0) |
| 264 | + { |
| 265 | + outRight = (sigmaRight[x -1] + add) >> 8; |
| 266 | + lastRight = outRight << 8; |
| 267 | + } |
| 268 | + else |
| 269 | + { |
| 270 | + outRight = (sigmaRight[x - 1] * -1 + add) >> 8; |
| 271 | + lastRight = outRight << 8; |
| 272 | + outRight *= -1; |
| 273 | + lastRight *= -1; |
| 274 | + } |
| 275 | + |
| 276 | + if (outLeft > 32767) outLeft = 32767; |
| 277 | + if (outLeft < -32768) outLeft = -32768; |
| 278 | + |
| 279 | + if (outRight > 32767) outRight = 32767; |
| 280 | + if (outRight < -32768) outRight = -32768; |
| 281 | + |
| 282 | + data2[i * 2] = (short)outLeft; |
| 283 | + data2[i * 2 + 1] = (short)outRight; |
| 284 | + |
| 285 | + p += 6; |
| 286 | + } |
| 287 | + |
| 288 | + ::WriteFile(fileHandle, data2, sample * 2 * 2, &writtenSize, NULL); |
| 289 | + ::FlushFileBuffers(fileHandle); // なくても大丈夫そう |
| 290 | + ::CloseHandle(fileHandle); |
| 291 | + |
| 292 | + ::GlobalFree(data2); |
| 293 | +} |
| 294 | + |
| 295 | +int _tmain(int argc, _TCHAR* argv[]) |
| 296 | +{ |
| 297 | + WAVEFORMATEX wf; |
| 298 | + DWORD offset, size, writtenSize = 0; |
| 299 | + void* data = 0; |
| 300 | + void* output = 0; |
| 301 | + |
| 302 | + wchar_t fileName[]= L"C:\\Test\\1k_174_24.wav"; |
| 303 | + wchar_t destFileName[] = L"C:\\Test\\out.wav"; |
| 304 | + |
| 305 | + searchFmtDataChunk(fileName, &wf, &offset, &size); |
| 306 | + data = readWavFile(fileName); |
| 307 | + |
| 308 | + |
| 309 | + int sample = size / ((wf.wBitsPerSample * wf.nChannels) / 8); |
| 310 | + if (wf.wBitsPerSample == 24 && wf.nChannels == 2) |
| 311 | + { |
| 312 | + noiseShaper(destFileName, data, sample, &wf, 12); |
| 313 | + } |
| 314 | + |
| 315 | + if (data) { |
| 316 | + ::GlobalFree(data); |
| 317 | + data = 0; |
| 318 | + } |
| 319 | + |
| 320 | + if (output) { |
| 321 | + ::GlobalFree(output); |
| 322 | + data = 0; |
| 323 | + } |
| 324 | + |
| 325 | + return 0; |
| 326 | +} |
| 327 | + |
0 commit comments