void SaveAudioClip(AudioProvider const& provider, fs::path const& path, int start_time, int end_time) { const auto max_samples = provider.GetNumSamples(); const auto start_sample = std::min(max_samples, ((int64_t)start_time * provider.GetSampleRate() + 999) / 1000); const auto end_sample = util::mid(start_sample, ((int64_t)end_time * provider.GetSampleRate() + 999) / 1000, max_samples); const size_t bytes_per_sample = provider.GetBytesPerSample() * provider.GetChannels(); const size_t bufsize = (end_sample - start_sample) * bytes_per_sample; writer out{path}; out.write("RIFF"); out.write<int32_t>(bufsize + 36); out.write("WAVEfmt "); out.write<int32_t>(16); // Size of chunk out.write<int16_t>(1); // compression format (PCM) out.write<int16_t>(provider.GetChannels()); out.write<int32_t>(provider.GetSampleRate()); out.write<int32_t>(provider.GetSampleRate() * provider.GetChannels() * provider.GetBytesPerSample()); out.write<int16_t>(provider.GetChannels() * provider.GetBytesPerSample()); out.write<int16_t>(provider.GetBytesPerSample() * 8); out.write("data"); out.write<int32_t>(bufsize); // samples per read size_t spr = 65536 / bytes_per_sample; std::vector<char> buf; for (int64_t i = start_sample; i < end_sample; i += spr) { spr = std::min<size_t>(spr, end_sample - i); buf.resize(spr * bytes_per_sample); provider.GetAudio(&buf[0], i, spr); out.write(buf); } }
////////////////////// // PortAudio callback int PortAudioPlayer::paCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) { // Get provider PortAudioPlayer *player = (PortAudioPlayer *) userData; AudioProvider *provider = player->GetProvider(); int end = 0; // Calculate how much left __int64 lenAvailable = player->endPos - player->playPos; uint64_t avail = 0; if (lenAvailable > 0) { avail = lenAvailable; if (avail > framesPerBuffer) { lenAvailable = framesPerBuffer; avail = lenAvailable; } } else { lenAvailable = 0; avail = 0; } // Play something if (lenAvailable > 0) { provider->GetAudio(outputBuffer,player->playPos,lenAvailable); } // Pad end with blank if (avail < (uint64_t) framesPerBuffer) { //provider->softStop = true; } // Set volume short *output = (short*) outputBuffer; for (unsigned int i=0;i<avail;i++) output[i] = MID(-(1<<15),int(output[i] * player->GetVolume()),(1<<15)-1); // Fill rest with blank for (unsigned int i=avail;i<framesPerBuffer;i++) output[i]=0; // Set play position (and real one) player->playPos += framesPerBuffer; player->realPlayPos = (__int64)(Pa_StreamTime(player->stream) - player->paStart) + player->startPos; // Cap to start if lower return end; }