| 411 | } |
| 412 | |
| 413 | NormalizedReferenceAudio normalize_reference_audio( |
| 414 | const runtime::AudioBuffer & audio, |
| 415 | const OmniVoiceAudioTokenizerConfig & config, |
| 416 | const OmniVoiceReferenceAudioOptions & options) { |
| 417 | auto mono = to_mono(audio); |
| 418 | if (audio.sample_rate != config.sample_rate) { |
| 419 | mono = resample_sinc_hann_mono(mono, audio.sample_rate, config.sample_rate); |
| 420 | } |
| 421 | NormalizedReferenceAudio normalized = {}; |
| 422 | normalized.reference_rms = engine::audio::root_mean_square_or_throw(mono); |
| 423 | if (normalized.reference_rms > 0.0F && normalized.reference_rms < kTargetReferenceRms) { |
| 424 | const float scale = kTargetReferenceRms / normalized.reference_rms; |
| 425 | for (float & sample : mono) { |
| 426 | sample *= scale; |
| 427 | } |
| 428 | } |
| 429 | mono = preprocess_reference_mono(std::move(mono), config.sample_rate, options); |
| 430 | |
| 431 | const int64_t hop_length = checked_positive(config.hop_length, "hop_length"); |
| 432 | const int64_t remainder = static_cast<int64_t>(mono.size()) % hop_length; |
| 433 | if (remainder > 0) { |
| 434 | mono.resize(mono.size() - static_cast<size_t>(remainder)); |
| 435 | } |
| 436 | if (mono.empty()) { |
| 437 | throw std::runtime_error("OmniVoice reference audio becomes empty after hop-length alignment"); |
| 438 | } |
| 439 | |
| 440 | normalized.frames = static_cast<int64_t>(mono.size()) / hop_length; |
| 441 | normalized.acoustic_samples_24k = mono; |
| 442 | auto semantic = resample_sinc_hann_mono(mono, config.sample_rate, config.semantic_sample_rate); |
| 443 | semantic.insert(semantic.begin(), 160, 0.0F); |
| 444 | semantic.insert(semantic.end(), 160, 0.0F); |
| 445 | normalized.semantic_samples_16k_padded = std::move(semantic); |
| 446 | return normalized; |
| 447 | } |
| 448 | |
| 449 | int64_t conv1d_output_length(int64_t input, int64_t kernel, int stride, int padding, int dilation) { |
| 450 | if (input <= 0 || kernel <= 0 || stride <= 0 || dilation <= 0) { |
no test coverage detected