| 311 | } |
| 312 | |
| 313 | std::vector<float> adapt_interleaved_audio( |
| 314 | const runtime::AudioBuffer & audio, |
| 315 | int target_sample_rate, |
| 316 | int target_channels, |
| 317 | int64_t target_frames) { |
| 318 | if (audio.sample_rate <= 0 || audio.channels <= 0 || target_sample_rate <= 0 || target_channels <= 0 || target_frames <= 0) { |
| 319 | throw std::runtime_error("Stable Audio SAME encode received invalid audio shape"); |
| 320 | } |
| 321 | if (audio.samples.size() % static_cast<size_t>(audio.channels) != 0) { |
| 322 | throw std::runtime_error("Stable Audio SAME encode audio samples are not divisible by channels"); |
| 323 | } |
| 324 | std::vector<float> samples = audio.samples; |
| 325 | int channels = audio.channels; |
| 326 | if (audio.sample_rate != target_sample_rate) { |
| 327 | const int64_t frames = static_cast<int64_t>(samples.size() / static_cast<size_t>(channels)); |
| 328 | std::vector<std::vector<float>> resampled_channels; |
| 329 | resampled_channels.reserve(static_cast<size_t>(channels)); |
| 330 | int64_t resampled_frames = -1; |
| 331 | for (int ch = 0; ch < channels; ++ch) { |
| 332 | std::vector<float> mono(static_cast<size_t>(frames), 0.0F); |
| 333 | for (int64_t frame = 0; frame < frames; ++frame) { |
| 334 | mono[static_cast<size_t>(frame)] = samples[static_cast<size_t>(frame * channels + ch)]; |
| 335 | } |
| 336 | engine::audio::SoxrResampleOptions options; |
| 337 | options.profile = engine::audio::SoxrResampleProfile::QualityOnly; |
| 338 | options.output_length_policy = engine::audio::SoxrOutputLengthPolicy::ExactExpected; |
| 339 | options.warning_context = "stable_audio.same_encode"; |
| 340 | options.fallback_description = "linear resampling"; |
| 341 | auto resampled = engine::audio::resample_mono_soxr_or_linear( |
| 342 | mono, |
| 343 | audio.sample_rate, |
| 344 | target_sample_rate, |
| 345 | options); |
| 346 | if (resampled_frames < 0) { |
| 347 | resampled_frames = static_cast<int64_t>(resampled.size()); |
| 348 | } else if (resampled_frames != static_cast<int64_t>(resampled.size())) { |
| 349 | throw std::runtime_error("Stable Audio SAME encode resampled channels have inconsistent lengths"); |
| 350 | } |
| 351 | resampled_channels.push_back(std::move(resampled)); |
| 352 | } |
| 353 | samples.assign(static_cast<size_t>(resampled_frames * channels), 0.0F); |
| 354 | for (int64_t frame = 0; frame < resampled_frames; ++frame) { |
| 355 | for (int ch = 0; ch < channels; ++ch) { |
| 356 | samples[static_cast<size_t>(frame * channels + ch)] = |
| 357 | resampled_channels[static_cast<size_t>(ch)][static_cast<size_t>(frame)]; |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | if (channels != target_channels) { |
| 362 | if (target_channels == 1) { |
| 363 | samples = engine::audio::mixdown_interleaved_to_mono_average(samples, channels); |
| 364 | } else if (channels == 1) { |
| 365 | samples = engine::audio::duplicate_mono_to_interleaved_channels(samples, target_channels); |
| 366 | } else { |
| 367 | auto mono = engine::audio::mixdown_interleaved_to_mono_average(samples, channels); |
| 368 | samples = engine::audio::duplicate_mono_to_interleaved_channels(mono, target_channels); |
| 369 | } |
| 370 | channels = target_channels; |
no test coverage detected