diff options
author | zeldakatze <coffee@zeldakatze.de> | 2025-08-10 21:50:27 +0200 |
---|---|---|
committer | zeldakatze <coffee@zeldakatze.de> | 2025-08-10 21:50:27 +0200 |
commit | 58f322541a08af7359420167c513e7ff396c1c9f (patch) | |
tree | 25183243a49b413ff32d0b60d0ac3d0bb6cc1ce2 | |
parent | 313f7f4c88500b4ae7c4dd765e18392bea0a2ba2 (diff) | |
download | abaddon-portaudio-58f322541a08af7359420167c513e7ff396c1c9f.tar.gz abaddon-portaudio-58f322541a08af7359420167c513e7ff396c1c9f.zip |
implement probably the worst resampler on earth
-rw-r--r-- | src/audio/manager.hpp | 8 | ||||
-rw-r--r-- | src/audio/portaudioManager.cpp | 53 |
2 files changed, 54 insertions, 7 deletions
diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp index a657dcc..2d1ae71 100644 --- a/src/audio/manager.hpp +++ b/src/audio/manager.hpp @@ -163,6 +163,14 @@ private: PaStream* pa_capture_device; PaStreamParameters m_capture_config; + // portaudio does not do resampling. We have to do that ourselves. + // create target buffers + int16_t *resample_capture_buffer; + int16_t *resample_playback_buffer; + uint32_t resample_capture_source_rate, resample_playback_source_rate; + uint32_t resample_capture_framesPerBuffer; + uint32_t resample_playback_framesPerBuffer; + #endif diff --git a/src/audio/portaudioManager.cpp b/src/audio/portaudioManager.cpp index bcd1254..56d32ed 100644 --- a/src/audio/portaudioManager.cpp +++ b/src/audio/portaudioManager.cpp @@ -10,19 +10,40 @@ #include <opus.h> #include <cstring> +// TODO replace with libresample +// a simple nearest-neigbhor resampler +static void resampleBuffer(const int16_t *input, const int inputFrames, + int16_t *output, const int outputFrames) { + float ratio = (float) inputFrames / (float) outputFrames; + inputFrames, outputFrames, ratio); + for(int oi = 0; oi < outputFrames; oi++) { + int ii = (int) (((float) oi) * ratio); + + // clamp the input index + if(ii >= inputFrames) { + ii = inputFrames - 1; + } + + // copy the samples. * 2 because stereo + output[oi * 2] = input[ii * 2]; + output[oi * 2 + 1] = input[ii * 2 + 1]; + } +} + int playCallback(const void *pInput, void *pOutput, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { AudioManager *mgr = reinterpret_cast<AudioManager *>(userData); - if (mgr == nullptr) {printf("NULL\n");return paContinue;}; + if (mgr == nullptr) {return paContinue;}; std::lock_guard<std::mutex> _(mgr->m_mutex); - auto *pOutputF32 = static_cast<int16_t *>(pOutput); + int16_t *resample_playback_buffer = mgr->resample_playback_buffer; + auto *pOutputF32 = static_cast<int16_t *>(resample_playback_buffer); /* clear the output buffer */ - for(int i = 0; i<frameCount * 2; i++) + for(int i = 0; i<480 * 2; i++) pOutputF32[i] = 0; /* write every SSRC into the output stream */ @@ -32,7 +53,7 @@ int playCallback(const void *pInput, void *pOutput, volume = vol_it->second; } auto &buf = pair.first; - const size_t n = std::min(static_cast<size_t>(buf.size()), static_cast<size_t>(frameCount * 2ULL)); + const size_t n = std::min(static_cast<size_t>(buf.size()), static_cast<size_t>(480 * 2ULL)); for (size_t i = 0; i < n; i++) { pOutputF32[i] += (int16_t) (volume * buf[i]); //pOutputF32[i] += volume * buf[i] / 32768.F; @@ -40,6 +61,9 @@ int playCallback(const void *pInput, void *pOutput, buf.erase(buf.begin(), buf.begin() + n); } + /* scale the resample buffer to the output buffer */ + resampleBuffer(resample_playback_buffer, 480, static_cast<int16_t *>(pOutput), frameCount); + return paContinue; } @@ -51,7 +75,11 @@ int recordCallback(const void *pInput, void *pOutput, auto *mgr = reinterpret_cast<AudioManager *>(userData); if (mgr == nullptr) return paContinue; - mgr->OnCapturedPCM(static_cast<const int16_t *>(pInput), frameCount); + int16_t *resample_capture_buffer = mgr->resample_capture_buffer; + + resampleBuffer(static_cast<const int16_t *>(pInput), frameCount, resample_capture_buffer, 480); + + mgr->OnCapturedPCM(static_cast<const int16_t *>(resample_capture_buffer), 480); /* * You can simply increment it by 480 in UDPSocket::SendEncrypted but this is wrong @@ -103,22 +131,30 @@ AudioManager::AudioManager(const Glib::ustring &backends_string) m_playback_config.suggestedLatency = Pa_GetDeviceInfo( m_capture_config.device )->defaultLowInputLatency; m_playback_config.hostApiSpecificStreamInfo = NULL; m_playback_config.device = Pa_GetDefaultOutputDevice(); + resample_playback_source_rate = Pa_GetDeviceInfo( m_playback_config.device )->defaultSampleRate; + resample_playback_framesPerBuffer = (int) (((float) resample_playback_source_rate / 48000.0) * 480.0); m_capture_config.sampleFormat = paInt16; m_capture_config.channelCount = 2; m_capture_config.suggestedLatency = Pa_GetDeviceInfo( m_capture_config.device )->defaultLowInputLatency; m_capture_config.hostApiSpecificStreamInfo = NULL; m_capture_config.device = Pa_GetDefaultInputDevice(); + resample_capture_source_rate = Pa_GetDeviceInfo( m_capture_config.device )->defaultSampleRate; + resample_capture_framesPerBuffer = (int) (((float) resample_capture_source_rate / 48000.0) * 480.0); + + /* initialize the buffers for resampling */ + resample_capture_buffer = (int16_t*) malloc(480 * 2 * sizeof(uint16_t)); + resample_playback_buffer = (int16_t*) malloc(480 * 2 * sizeof(uint16_t)); /* create the streams */ - pa_err = Pa_OpenStream(&pa_capture_device, &m_capture_config, NULL, 48000, 480, paClipOff, recordCallback, this); + pa_err = Pa_OpenStream(&pa_capture_device, &m_capture_config, NULL, resample_capture_source_rate, resample_capture_framesPerBuffer, paClipOff, recordCallback, this); if(pa_err != paNoError) { m_ok = false; spdlog::get("audio")->error("ERROR: Pa_OpenStream for capture returned %d\n", pa_err); return; } - pa_err = Pa_OpenStream(&pa_playback_device, NULL, &m_playback_config, 48000, 480, paClipOff, playCallback, this); + pa_err = Pa_OpenStream(&pa_playback_device, NULL, &m_playback_config, resample_playback_source_rate, resample_playback_framesPerBuffer, paClipOff, playCallback, this); if(pa_err != paNoError) { m_ok = false; spdlog::get("audio")->error("ERROR: Pa_OpenStream for playback returned %d\n", pa_err); @@ -140,6 +176,9 @@ AudioManager::AudioManager(const Glib::ustring &backends_string) AudioManager::~AudioManager() { Pa_Terminate(); RemoveAllSSRCs(); + + free(resample_capture_buffer); + free(resample_playback_buffer); #ifdef WITH_RNNOISE RNNoiseUninitialize(); |