| 205 | } |
| 206 | |
| 207 | engine::io::json::Value audio_summary_json(const engine::runtime::AudioBuffer & audio) { |
| 208 | if (audio.samples.empty()) { |
| 209 | throw std::runtime_error("Stable Audio warmbench received empty audio output"); |
| 210 | } |
| 211 | double sum = 0.0; |
| 212 | double abs_sum = 0.0; |
| 213 | double sq_sum = 0.0; |
| 214 | float min_value = audio.samples.front(); |
| 215 | float max_value = audio.samples.front(); |
| 216 | for (const float sample : audio.samples) { |
| 217 | sum += static_cast<double>(sample); |
| 218 | abs_sum += std::abs(static_cast<double>(sample)); |
| 219 | sq_sum += static_cast<double>(sample) * static_cast<double>(sample); |
| 220 | min_value = std::min(min_value, sample); |
| 221 | max_value = std::max(max_value, sample); |
| 222 | } |
| 223 | const auto channels = std::max(1, audio.channels); |
| 224 | const double frames = static_cast<double>(audio.samples.size() / static_cast<size_t>(channels)); |
| 225 | const double count = static_cast<double>(audio.samples.size()); |
| 226 | return engine::io::json::Value::make_object({ |
| 227 | {"sample_rate", number(static_cast<double>(audio.sample_rate))}, |
| 228 | {"channels", number(static_cast<double>(audio.channels))}, |
| 229 | {"samples", number(count)}, |
| 230 | {"frames", number(frames)}, |
| 231 | {"duration_sec", number(audio.sample_rate > 0 ? frames / audio.sample_rate : 0.0)}, |
| 232 | {"sum", number(sum)}, |
| 233 | {"mean_abs", number(abs_sum / count)}, |
| 234 | {"rms", number(std::sqrt(sq_sum / count))}, |
| 235 | {"min", number(min_value)}, |
| 236 | {"max", number(max_value)}, |
| 237 | }); |
| 238 | } |
| 239 | |
| 240 | engine::io::json::Value step_json( |
| 241 | const engine::runtime::TaskResult & result, |