载入中...
搜索中...
未找到
AudioTransport.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::audio_editing {
7namespace {} // namespace
8
10 if (asset.empty() || revision == 0 || !backend)
11 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.audio.transport-bind"),
12 "Audition requires asset identity, revision and playback backend");
13 const double duration = backend->duration();
14 if (!std::isfinite(duration) || duration <= 0.0)
15 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.audio.transport-duration"),
16 "Audition source requires a finite positive duration");
17 unbind();
18 asset_ = std::move(asset);
19 revision_ = revision;
20 backend_ = backend;
21 backend_->setNativeLooping(false);
22 return eve::editing::applied<void>();
23}
24Result<void> AudioAuditionTransport::validateRevision(Revision expected) const {
25 if (!backend_)
26 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.audio.transport-unbound"),
27 "No audition source is bound");
28 if (expected != revision_)
29 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.audio.transport-stale"),
30 "Audition source revision is stale");
31 return eve::editing::applied<void>();
32}
34 double end) {
35 auto valid = validateRevision(expected);
36 if (!valid.ok()) return valid;
37 const double duration = backend_->duration();
38 if (end == 0.0) end = duration;
39 if (!std::isfinite(start) || !std::isfinite(end) || start < 0.0 || end <= start || end > duration)
40 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.audio.transport-loop-range"),
41 "Loop range must be finite, ordered and inside the clip");
42 loopEnabled_ = enabled;
43 loopStart_ = start;
44 loopEnd_ = end;
45 backend_->setNativeLooping(false);
46 return eve::editing::applied<void>();
47}
49 auto valid = validateRevision(expected);
50 if (!valid.ok()) return valid;
51 if (loopEnabled_ && (backend_->tell() < loopStart_ || backend_->tell() >= loopEnd_)) {
52 auto seekResult = backend_->seek(loopStart_);
53 if (!seekResult.ok()) return seekResult;
54 }
55 backend_->play();
57 return eve::editing::applied<void>();
58}
60 auto valid = validateRevision(expected);
61 if (!valid.ok()) return valid;
62 if (state_ != AudioTransportState::Playing) {
63 return eve::editing::noOp();
64 }
65 backend_->pause();
67 return eve::editing::applied<void>();
68}
70 auto valid = validateRevision(expected);
71 if (!valid.ok()) return valid;
72 if (state_ == AudioTransportState::Stopped) {
73 return eve::editing::noOp();
74 }
75 backend_->stop();
77 return eve::editing::applied<void>();
78}
79Result<void> AudioAuditionTransport::seek(Revision expected, double seconds) {
80 auto valid = validateRevision(expected);
81 if (!valid.ok()) return valid;
82 const double duration = backend_->duration();
83 if (!std::isfinite(seconds) || seconds < 0.0 || seconds > duration)
84 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.audio.transport-seek-range"),
85 "Seek position must be inside the clip");
86 return backend_->seek(seconds);
87}
88AudioTransportSnapshot AudioAuditionTransport::observe() const {
89 return {asset_,
90 revision_,
91 state_,
92 backend_ ? std::clamp(backend_->tell(), 0.0, backend_->duration()) : 0.0,
93 backend_ ? backend_->duration() : 0.0,
94 loopEnabled_,
95 loopStart_,
96 loopEnd_};
97}
99 auto valid = validateRevision(expected);
100 if (!valid.ok())
101 return eve::editing::failed<AudioTransportSnapshot>(valid.code(), RuleId("editor.audio.transport-stale"),
102 "Audition source is absent or stale");
103 return eve::editing::applied<AudioTransportSnapshot>(observe());
104}
106 auto valid = validateRevision(expected);
107 if (!valid.ok()) {
108 const EditorStatus status = valid.code();
109 if (status == EditorStatus::Conflict) unbind();
110 return eve::editing::failed<AudioTransportSnapshot>(status, RuleId("editor.audio.transport-stale"),
111 "Audition source is absent or stale");
112 }
113 if (state_ == AudioTransportState::Playing && loopEnabled_ && backend_->tell() >= loopEnd_) {
114 auto seekResult = backend_->seek(loopStart_);
115 if (!seekResult.ok())
116 return eve::editing::failed<AudioTransportSnapshot>(
117 seekResult.code(), RuleId("editor.audio.transport-loop-seek"), "Playback backend cannot wrap the loop");
118 backend_->play();
119 } else if (state_ == AudioTransportState::Playing && !backend_->playing() &&
120 backend_->tell() >= backend_->duration()) {
122 }
123 return eve::editing::applied<AudioTransportSnapshot>(observe());
124}
126 if (backend_) backend_->stop();
127 backend_ = nullptr;
128 asset_ = StableId{};
129 revision_ = 0;
131 loopEnabled_ = false;
132 loopStart_ = loopEnd_ = 0.0;
133}
134
135} // namespace eve::audio_editing
Duration start
float duration
wgpu::PopErrorScopeStatus status
bool valid
std::uint64_t revision
Move-only operation result carrying either a value or Status.
Definition Result.h:155
Result< void > pause(Revision expectedRevision)
Pause.
Result< AudioTransportSnapshot > snapshot(Revision expectedRevision) const
Read the current playhead only for the bound source revision.
Result< void > setLoop(Revision expectedRevision, bool enabled, double startSeconds=0.0, double endSeconds=0.0)
Configure a bounded loop range; zero end uses the clip duration.
Result< void > bind(StableId asset, Revision sourceRevision, IAudioTransportBackend *backend)
Bind a borrowed backend and stop any previously bound audition.
Result< void > stop(Revision expectedRevision)
Stops .
void unbind()
Stop and forget the borrowed backend.
Result< void > seek(Revision expectedRevision, double seconds)
Seeks .
Result< AudioTransportSnapshot > update(Revision expectedRevision)
Poll backend state and wrap the custom loop without changing documents.
Result< void > play(Revision expectedRevision)
Play.
Minimal playback backend boundary used by the deterministic transport controller.
virtual void setNativeLooping(bool enabled)=0
Sets the native looping.
virtual double duration() const =0
Duration.
virtual Result< void > seek(double seconds)=0
Seek the backend playhead.
virtual bool playing() const =0
Playing.
virtual double tell() const =0
Tell.
Result< void > noOp(std::vector< Diagnostic > diagnostics={})
Construct a successful void result for an operation that made no change.
StatusCode
Stable outcome category for an operation.
Definition Status.h:27
bool enabled
Immutable revision-tagged audition playhead observation.