| 277 | return plan_vad_audio_chunks( |
| 278 | vad_result.speech_segments, |
| 279 | static_cast<int64_t>(audio.samples.size() / static_cast<size_t>(audio.channels)), |
| 280 | options); |
| 281 | } |
| 282 | |
| 283 | std::vector<runtime::TimeSpan> plan_quiet_energy_audio_chunks( |
| 284 | const std::vector<float> & mono_samples, |
| 285 | const QuietEnergyAudioChunkOptions & options) { |
| 286 | require_positive(static_cast<int64_t>(mono_samples.size()), "quiet-energy input samples"); |
| 287 | require_positive(options.chunk_samples, "quiet-energy chunk samples"); |
| 288 | require_positive(options.boundary_context_samples, "quiet-energy boundary context samples"); |
| 289 | require_positive(options.min_energy_window_samples, "quiet-energy min energy window samples"); |
| 290 | |
| 291 | const int64_t total = static_cast<int64_t>(mono_samples.size()); |
| 292 | std::vector<runtime::TimeSpan> chunks; |
| 293 | int64_t index = 0; |
| 294 | while (index < total) { |
| 295 | if (index + options.chunk_samples >= total) { |
| 296 | chunks.push_back({index, total}); |
| 297 | break; |
| 298 | } |
| 299 | const int64_t search_start = std::max(index, index + options.chunk_samples - options.boundary_context_samples); |
| 300 | const int64_t search_end = std::min(index + options.chunk_samples, total); |
| 301 | int64_t split = index + options.chunk_samples; |
| 302 | if (search_end > search_start) { |
| 303 | if (search_end - search_start <= options.min_energy_window_samples) { |
| 304 | split = (search_start + search_end) / 2; |
| 305 | } else { |
| 306 | float min_energy = std::numeric_limits<float>::infinity(); |
| 307 | const int64_t upper = search_end - search_start - options.min_energy_window_samples; |