| 340 | } |
| 341 | |
| 342 | std::shared_ptr<ft0cc::doc::dpcm_sample> CPCMImport::ConvertFile() { // // // |
| 343 | // Converts a WAV file to a DPCM sample |
| 344 | const int DMC_BIAS = 32; |
| 345 | |
| 346 | unsigned char DeltaAcc = 0; // DPCM sample accumulator |
| 347 | int Delta = DMC_BIAS; // Delta counter |
| 348 | int AccReady = 8; |
| 349 | |
| 350 | float volume = powf(10, float(m_iVolume) / 20.0f); // Convert dB to linear |
| 351 | |
| 352 | // Seek to start of samples |
| 353 | m_fSampleFile.Seek(m_ullSampleStart, CFile::begin); |
| 354 | |
| 355 | // Allocate space |
| 356 | std::vector<uint8_t> pSamples(ft0cc::doc::dpcm_sample::max_size); // // // |
| 357 | |
| 358 | // Determine resampling factor |
| 359 | float base_freq = (float)MASTER_CLOCK_NTSC / (float)CDPCM::DMC_PERIODS_NTSC[m_iQuality]; |
| 360 | float resample_factor = base_freq / (float)m_iSamplesPerSec; |
| 361 | |
| 362 | resampler resmpler(*m_psinc, resample_factor, m_iChannels, m_iSampleSize, m_iWaveSize, m_fSampleFile); |
| 363 | float val; |
| 364 | // Conversion |
| 365 | while (resmpler.get(val) && (pSamples.size() < ft0cc::doc::dpcm_sample::max_size)) { // // // |
| 366 | |
| 367 | // when resampling we must clip because of possible ringing. |
| 368 | const float MAX_AMP = (1 << 16) - 1; |
| 369 | const float MIN_AMP = -(1 << 16) + 1; // just being symetric |
| 370 | val = std::clamp(val, MIN_AMP, MAX_AMP); |
| 371 | |
| 372 | // Volume done this way so it acts as before |
| 373 | int Sample = (int)((val * volume) / 1024.f) + DMC_BIAS; |
| 374 | |
| 375 | DeltaAcc >>= 1; |
| 376 | |
| 377 | // PCM -> DPCM |
| 378 | if (Sample >= Delta) { |
| 379 | ++Delta; |
| 380 | if (Delta > 63) |
| 381 | Delta = 63; |
| 382 | DeltaAcc |= 0x80; |
| 383 | } |
| 384 | else if (Sample < Delta) { |
| 385 | --Delta; |
| 386 | if (Delta < 0) |
| 387 | Delta = 0; |
| 388 | } |
| 389 | |
| 390 | if (--AccReady == 0) { |
| 391 | // Store sample |
| 392 | pSamples.push_back(DeltaAcc); |
| 393 | AccReady = 8; |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | // TODO: error handling with th efile |
| 398 | // if (!resmpler.eof()) |
| 399 | // throw ?? or something else. |