载入中...
搜索中...
未找到
AudioImportDiagnostics.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <limits>
6
7namespace eve::audio_editing {
8
10 const AudioImportInspectionRequest& request, const EditorAudioPcm& pcm) const {
12 result.asset = request.asset; result.sourceRevision = request.sourceRevision;
13 if (request.asset.empty() || request.sourceRevision == 0 || request.codec.empty() ||
14 pcm.sampleRate < 8000 || pcm.sampleRate > 384000 || pcm.channels < 1 || pcm.channels > 8 ||
15 pcm.samples.empty() || pcm.samples.size() % static_cast<std::size_t>(pcm.channels) != 0 ||
16 pcm.samples.size() > request.maximumSamples || request.maximumSamples == 0 ||
17 !std::isfinite(request.clippingThreshold) || request.clippingThreshold <= 0.0 ||
18 request.clippingThreshold > 1.0 || !std::isfinite(request.silenceThreshold) ||
19 request.silenceThreshold < 0.0 || request.silenceThreshold >= request.clippingThreshold) {
20 result.status = EditorStatus::Rejected;
22 eve::DiagnosticCode::InvalidArgument, RuleId("editor.audio.invalid-import-inspection"),
23 DiagnosticSeverity::Error,
24 "Audio inspection requires valid identity, format, thresholds and bounded PCM"));
25 return result;
26 }
27 const std::size_t frames = pcm.samples.size() / static_cast<std::size_t>(pcm.channels);
28 result.duration = static_cast<double>(frames) / static_cast<double>(pcm.sampleRate);
29 if (pcm.samples.size() > std::numeric_limits<std::size_t>::max() / sizeof(float)) {
30 result.status = EditorStatus::Rejected;
32 eve::DiagnosticCode::InvalidArgument, RuleId("editor.audio.decoded-size-overflow"),
33 DiagnosticSeverity::Error, "Decoded audio size exceeds the host range"));
34 return result;
35 }
36 result.decodedBytes = pcm.samples.size() * sizeof(float);
37 result.compressionRatio = request.encodedBytes > 0
38 ? static_cast<double>(result.decodedBytes) / static_cast<double>(request.encodedBytes) : 0.0;
39 result.recommendStreaming = result.decodedBytes > request.staticMemoryBudget || result.duration > 10.0;
40 result.channels.resize(static_cast<std::size_t>(pcm.channels));
41 std::vector<long double> squares(result.channels.size(), 0.0L);
42 std::vector<long double> sums(result.channels.size(), 0.0L);
43 for (std::size_t frame = 0; frame < frames; ++frame) {
44 for (int channel = 0; channel < pcm.channels; ++channel) {
45 const float sample = pcm.samples[frame * static_cast<std::size_t>(pcm.channels) +
46 static_cast<std::size_t>(channel)];
47 if (!std::isfinite(sample)) {
48 result.status = EditorStatus::Rejected;
50 eve::DiagnosticCode::InvalidArgument, RuleId("editor.audio.nonfinite-sample"),
51 DiagnosticSeverity::Error, "Decoded PCM contains a non-finite sample"));
52 return result;
53 }
54 auto& statistics = result.channels[static_cast<std::size_t>(channel)];
55 const double absolute = std::abs(static_cast<double>(sample));
56 statistics.peak = std::max(statistics.peak, absolute);
57 if (absolute >= request.clippingThreshold) ++statistics.clippedSamples;
58 sums[static_cast<std::size_t>(channel)] += sample;
59 squares[static_cast<std::size_t>(channel)] += static_cast<long double>(sample) * sample;
60 }
61 }
62 bool silent = true;
63 for (std::size_t channel = 0; channel < result.channels.size(); ++channel) {
64 auto& statistics = result.channels[channel];
65 statistics.dcOffset = static_cast<double>(sums[channel] / frames);
66 statistics.rms = std::sqrt(static_cast<double>(squares[channel] / frames));
67 silent = silent && statistics.peak <= request.silenceThreshold;
68 if (statistics.clippedSamples > 0)
70 eve::DiagnosticCode::PreconditionViolation, RuleId("editor.audio.clipping"),
71 DiagnosticSeverity::Warning,
72 "Audio channel " + std::to_string(channel) + " contains clipped samples"));
73 if (std::abs(statistics.dcOffset) > 0.01)
75 eve::DiagnosticCode::PreconditionViolation, RuleId("editor.audio.dc-offset"),
76 DiagnosticSeverity::Warning,
77 "Audio channel " + std::to_string(channel) + " has significant DC offset"));
78 }
79 if (silent)
81 eve::DiagnosticCode::PreconditionViolation, RuleId("editor.audio.silence"),
82 DiagnosticSeverity::Warning, "Decoded audio is effectively silent"));
83 if (result.recommendStreaming && !request.streaming)
86 RuleId("editor.audio.streaming-recommended"), DiagnosticSeverity::Warning,
87 "Long or memory-heavy audio should use streaming playback"));
88 if (!result.recommendStreaming && request.streaming)
90 eve::DiagnosticCode::None, RuleId("editor.audio.static-recommended"),
91 DiagnosticSeverity::Info, "Short audio can avoid streaming overhead"));
92 result.status = EditorStatus::Applied;
93 return result;
94}
95
96} // namespace eve::audio_editing
const GltfImportRequest & request
AudioImportInspectionResult inspect(const AudioImportInspectionRequest &request, const EditorAudioPcm &pcm) const
Inspect.
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
Import metadata and policy supplied before audio publication.
Revision-tagged codec/import QA and memory recommendation.
std::vector< AudioChannelInspection > channels
Decoded interleaved PCM supplied by an audio importer or codec plugin.