|
13 | 13 | #include <cmath> |
14 | 14 | #include <limits> |
15 | 15 | #include <vector> |
| 16 | +#ifdef LIBROSA_HAS_SOXR |
| 17 | +#include <soxr.h> |
| 18 | +#endif |
16 | 19 | #include "../internal/fft.hpp" |
17 | 20 |
|
18 | 21 | namespace librosa { |
@@ -285,6 +288,10 @@ namespace { |
285 | 288 | res_type == "kaiser_fast"; |
286 | 289 | } |
287 | 290 |
|
| 291 | + bool is_soxr_resampler(const std::string& res_type) { |
| 292 | + return res_type.rfind("soxr", 0) == 0; |
| 293 | + } |
| 294 | + |
288 | 295 | SincResamplerSpec kaiser_resampler_spec(const std::string& res_type) { |
289 | 296 | if (res_type == "kaiser_vhq") { |
290 | 297 | return {96, 16.0, 0.975}; |
@@ -373,6 +380,57 @@ namespace { |
373 | 380 |
|
374 | 381 | return y_hat; |
375 | 382 | } |
| 383 | + |
| 384 | +#ifdef LIBROSA_HAS_SOXR |
| 385 | + unsigned long soxr_quality_recipe(const std::string& res_type) { |
| 386 | + if (res_type == "soxr_vhq") return SOXR_VHQ; |
| 387 | + if (res_type == "soxr_hq") return SOXR_HQ; |
| 388 | + if (res_type == "soxr_mq") return SOXR_MQ; |
| 389 | + if (res_type == "soxr_lq") return SOXR_LQ; |
| 390 | + if (res_type == "soxr_qq") return SOXR_QQ; |
| 391 | + throw ParameterError("Unknown SOXR resampling type: " + res_type); |
| 392 | + } |
| 393 | + |
| 394 | + ArrayXr soxr_resample(const ArrayXr& y, Real orig_sr, Real target_sr, |
| 395 | + Eigen::Index n_samples, const std::string& res_type) { |
| 396 | + ArrayXr y_hat(n_samples); |
| 397 | + if (n_samples == 0) { |
| 398 | + return y_hat; |
| 399 | + } |
| 400 | + |
| 401 | + soxr_io_spec_t io_spec = soxr_io_spec(SOXR_FLOAT64_I, SOXR_FLOAT64_I); |
| 402 | + soxr_quality_spec_t quality_spec = |
| 403 | + soxr_quality_spec(soxr_quality_recipe(res_type), 0); |
| 404 | + soxr_runtime_spec_t runtime_spec = soxr_runtime_spec(1); |
| 405 | + |
| 406 | + size_t idone = 0; |
| 407 | + size_t odone = 0; |
| 408 | + soxr_error_t err = soxr_oneshot( |
| 409 | + static_cast<double>(orig_sr), |
| 410 | + static_cast<double>(target_sr), |
| 411 | + 1, |
| 412 | + y.data(), |
| 413 | + static_cast<size_t>(y.size()), |
| 414 | + &idone, |
| 415 | + y_hat.data(), |
| 416 | + static_cast<size_t>(n_samples), |
| 417 | + &odone, |
| 418 | + &io_spec, |
| 419 | + &quality_spec, |
| 420 | + &runtime_spec); |
| 421 | + |
| 422 | + if (err) { |
| 423 | + throw ParameterError(std::string("SOXR resampling failed: ") + |
| 424 | + soxr_strerror(err)); |
| 425 | + } |
| 426 | + |
| 427 | + if (odone != static_cast<size_t>(y_hat.size())) { |
| 428 | + y_hat.conservativeResize(static_cast<Eigen::Index>(odone)); |
| 429 | + } |
| 430 | + |
| 431 | + return y_hat; |
| 432 | + } |
| 433 | +#endif |
376 | 434 | } |
377 | 435 |
|
378 | 436 | // ============================================================================ |
@@ -603,6 +661,13 @@ ArrayXr resample(const ArrayXr& y, Real orig_sr, Real target_sr, |
603 | 661 |
|
604 | 662 | if (is_kaiser_resampler(res_type)) { |
605 | 663 | y_hat = kaiser_sinc_resample(y, ratio, n_samples, kaiser_resampler_spec(res_type)); |
| 664 | + } else if (is_soxr_resampler(res_type)) { |
| 665 | +#ifdef LIBROSA_HAS_SOXR |
| 666 | + y_hat = soxr_resample(y, orig_sr, target_sr, n_samples, res_type); |
| 667 | +#else |
| 668 | + throw ParameterError( |
| 669 | + "SOXR resampling requires configuring with -DLIBROSA_USE_SOXR=ON"); |
| 670 | +#endif |
606 | 671 | } else if (res_type == "fft" || res_type == "scipy") { |
607 | 672 | int n_fft = y.size(); |
608 | 673 | int n_out = n_samples; |
|
0 commit comments