Skip to content

Commit c38c90d

Browse files
authored
v2.2.0 (#17)
1 parent 1ecf2a4 commit c38c90d

19 files changed

Lines changed: 514 additions & 412 deletions

Packages/AudioConductor/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## v2.2.0 - 2026/05/19
4+
5+
- New Features
6+
- Open AudioClip property inspector from TrackInspector
7+
8+
- Fix Issues
9+
- Fix CueSheet assets not found when asset cache was initialized as empty
10+
311
## v2.1.1 - 2026/05/14
412

513
- Fix Issues

Packages/AudioConductor/Editor/Core/Tools/CueSheetEditor/Presenters/TrackInspectorPresenter.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using AudioConductor.Editor.Core.Tools.CueSheetEditor.Models.Interfaces;
1010
using AudioConductor.Editor.Core.Tools.CueSheetEditor.Views;
1111
using AudioConductor.Editor.Foundation.TinyRx;
12+
using UnityEditor;
1213
using UnityEngine.Assertions;
1314

1415
namespace AudioConductor.Editor.Core.Tools.CueSheetEditor.Presenters
@@ -74,6 +75,9 @@ private void Bind()
7475
model.AudioClipObservable
7576
.Subscribe(_view.SetSampleRange)
7677
.DisposeWith(_bindDisposable);
78+
model.AudioClipObservable
79+
.Subscribe(value => _view.SetOpenAudioClipInspectorButtonEnabled(value.Value != null))
80+
.DisposeWith(_bindDisposable);
7781
model.VolumeObservable
7882
.Subscribe(_view.SetVolume)
7983
.DisposeWith(_bindDisposable);
@@ -168,6 +172,14 @@ private void SetupViewEventHandlers()
168172
_view.AnalyzeClickedAsObservable
169173
.Subscribe(_ => model.AnalyzeWaveChunk())
170174
.DisposeWith(_viewEventDisposable);
175+
_view.OpenAudioClipInspectorClickedAsObservable
176+
.Subscribe(_ =>
177+
{
178+
var clip = model.AudioClip;
179+
if (clip is not null)
180+
EditorUtility.OpenPropertyEditor(clip);
181+
})
182+
.DisposeWith(_viewEventDisposable);
171183
_view.PlayRequestedAsObservable
172184
.Subscribe(sample => { _view.SetController(model.PlayClip(sample)); })
173185
.DisposeWith(_viewEventDisposable);

Packages/AudioConductor/Editor/Core/Tools/CueSheetEditor/Views/TrackInspectorView.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ internal sealed partial class TrackInspectorView : VisualElement, IDisposable
3636

3737
private readonly Subject<string> _nameChangedSubject = new();
3838
private readonly TextField _nameField;
39+
private readonly Button _openAudioClipInspectorButton;
40+
private readonly Subject<Empty> _openAudioClipInspectorClickedSubject = new();
3941
private readonly Button _pauseButton;
4042
private readonly Subject<float> _pitchChangedSubject = new();
4143
private readonly SliderAndFloatField _pitchField;
@@ -81,6 +83,9 @@ public TrackInspectorView()
8183
_isLoopField = this.Q<Toggle>("Loop");
8284
_loopStartSampleField = this.Q<SliderAndIntegerField>("LoopStartSample");
8385
_analyzeButton = this.Q<Button>("Analyze");
86+
_openAudioClipInspectorButton = this.Q<Button>("OpenAudioClipInspector");
87+
_openAudioClipInspectorButton.style.backgroundImage =
88+
new StyleBackground((Texture2D)EditorGUIUtility.IconContent("d_UnityEditor.InspectorWindow").image);
8489
_playButton = this.Q<Button>("Play");
8590
_pauseButton = this.Q<Button>("Pause");
8691
_pauseButton.style.backgroundImage =
@@ -118,6 +123,7 @@ public TrackInspectorView()
118123
internal IObservable<bool> IsLoopChangedAsObservable => _isLoopChangedSubject;
119124
internal IObservable<int> LoopStartSampleChangedAsObservable => _loopStartSampleChangedSubject;
120125
internal IObservable<Empty> AnalyzeClickedAsObservable => _analyzeClickedSubject;
126+
internal IObservable<Empty> OpenAudioClipInspectorClickedAsObservable => _openAudioClipInspectorClickedSubject;
121127
internal IObservable<int?> PlayRequestedAsObservable => _playRequestedSubject;
122128

123129
public void Dispose()
@@ -193,6 +199,7 @@ private void SetupEventHandlers()
193199
_isLoopField.RegisterValueChangedCallback(OnIsLoopChanged);
194200
_loopStartSampleField.RegisterValueChangedCallback(OnLoopStartSampleChanged);
195201
_analyzeButton.RegisterCallback<ClickEvent>(OnAnalyzeButtonClicked);
202+
_openAudioClipInspectorButton.RegisterCallback<ClickEvent>(OnOpenAudioClipInspectorButtonClicked);
196203
_playButton.RegisterCallback<ClickEvent>(OnPlayButtonClicked);
197204
_pauseButton.RegisterCallback<ClickEvent>(OnPauseButtonClicked);
198205
_stopButton.RegisterCallback<ClickEvent>(OnStopButtonClicked);
@@ -203,6 +210,7 @@ private void CleanupEventHandlers()
203210
_stopButton.UnregisterCallback<ClickEvent>(OnStopButtonClicked);
204211
_pauseButton.UnregisterCallback<ClickEvent>(OnPauseButtonClicked);
205212
_playButton.UnregisterCallback<ClickEvent>(OnPlayButtonClicked);
213+
_openAudioClipInspectorButton.UnregisterCallback<ClickEvent>(OnOpenAudioClipInspectorButtonClicked);
206214
_analyzeButton.UnregisterCallback<ClickEvent>(OnAnalyzeButtonClicked);
207215
_loopStartSampleField.UnregisterValueChangedCallback(OnLoopStartSampleChanged);
208216
_isLoopField.UnregisterValueChangedCallback(OnIsLoopChanged);
@@ -347,6 +355,11 @@ internal void SetLoopStartSample(MixedValue<int> value)
347355
_loopStartSampleField.showMixedValue = value.HasMultipleDifferentValues;
348356
}
349357

358+
internal void SetOpenAudioClipInspectorButtonEnabled(bool enabled)
359+
{
360+
_openAudioClipInspectorButton.SetEnabled(enabled);
361+
}
362+
350363
internal void SetSampleRange(MixedValue<AudioClip?> value)
351364
{
352365
var audioClip = value.Value;
@@ -453,6 +466,11 @@ private void OnAnalyzeButtonClicked(ClickEvent _)
453466
_analyzeClickedSubject.OnNext(Empty.Default);
454467
}
455468

469+
private void OnOpenAudioClipInspectorButtonClicked(ClickEvent _)
470+
{
471+
_openAudioClipInspectorClickedSubject.OnNext(Empty.Default);
472+
}
473+
456474
private void OnPlayButtonClicked(ClickEvent _)
457475
{
458476
_playRequestedSubject.OnNext(null);

Packages/AudioConductor/Editor/Core/Tools/Shared/CueSheetAssetRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal sealed class CueSheetAssetRepository : ScriptableSingleton<CueSheetAsse
2121
/// </summary>
2222
public CueSheetAsset[] GetAll()
2323
{
24-
if (_all is null)
24+
if (_all is null || _all.Length == 0)
2525
_all = LoadAll();
2626
return _all;
2727
}

Packages/AudioConductor/Editor/PackageResources/Uxml/TrackInspector.uxml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
22
<ui:TextField picking-mode="Ignore" label="Track Name" value="filler text" name="Name" is-delayed="true" />
33
<AudioConductor.Editor.Core.Tools.Shared.ColorDefinePopupField label="Color" />
4-
<uie:ObjectField label="Audio Clip" allow-scene-objects="false" type="UnityEngine.AudioClip, UnityEngine.AudioModule" name="AudioClip" />
4+
<ui:VisualElement style="flex-direction: row; align-items: flex-end;">
5+
<uie:ObjectField label="Audio Clip" allow-scene-objects="false" type="UnityEngine.AudioClip, UnityEngine.AudioModule" name="AudioClip" style="flex: 1;" />
6+
<ui:Button name="OpenAudioClipInspector" style="width: 18px; height: 18px; padding: 0; margin-left: 2px; margin-bottom: 1px;" />
7+
</ui:VisualElement>
58
<AudioConductor.Editor.Core.Tools.Shared.SliderAndFloatField label="Volume" value="1" high-value="1" name="Volume" />
69
<AudioConductor.Editor.Core.Tools.Shared.SliderAndFloatField label="Volume Range" high-value="1" name="VolumeRange" />
710
<AudioConductor.Editor.Core.Tools.Shared.SliderAndFloatField label="Pitch" high-value="3" value="1" low-value="0.01" name="Pitch" />

Packages/AudioConductor/Runtime/Core/Conductor.Playback.cs

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -347,65 +347,40 @@ private bool CanPlay(uint cueSheetId, Cue cue, Track track)
347347
return true;
348348

349349
// Single pass: count playing states and track oldest per scope at once.
350-
int cueCount = 0, sheetCount = 0, catCount = 0, globalCount = 0;
351-
int cueMin = int.MaxValue, sheetMin = int.MaxValue, catMin = int.MaxValue, globalMin = int.MaxValue;
352-
Playback? cueOldest = null, sheetOldest = null, catOldest = null, globalOldest = null;
350+
var ctx = new ThrottleContext(cueSheetId, cue);
353351

354352
foreach (var p in _managedPlaybacks.Values)
355-
ThrottleResolver.AccumulateAllScopes(p.Core, cueSheetId, cue, cue.categoryId,
356-
ref cueCount, ref cueMin, ref cueOldest,
357-
ref sheetCount, ref sheetMin, ref sheetOldest,
358-
ref catCount, ref catMin, ref catOldest,
359-
ref globalCount, ref globalMin, ref globalOldest);
353+
ctx.Accumulate(p.Core);
360354

361355
foreach (var s in _oneShotPlaybacks)
362-
ThrottleResolver.AccumulateAllScopes(s.Core, cueSheetId, cue, cue.categoryId,
363-
ref cueCount, ref cueMin, ref cueOldest,
364-
ref sheetCount, ref sheetMin, ref sheetOldest,
365-
ref catCount, ref catMin, ref catOldest,
366-
ref globalCount, ref globalMin, ref globalOldest);
356+
ctx.Accumulate(s.Core);
367357

368358
#if UNITY_EDITOR
369359
// Invariant: counts must not exceed their respective limits.
370360
// Violated only if throttle limits are mutated while players are active (unsupported).
371-
Debug.Assert(cueThrottleLimit <= 0 || cueCount <= cueThrottleLimit,
361+
Debug.Assert(cueThrottleLimit <= 0 || ctx.CueCount <= cueThrottleLimit,
372362
"cue count exceeds throttle limit");
373-
Debug.Assert(sheetThrottleLimit <= 0 || sheetCount <= sheetThrottleLimit,
363+
Debug.Assert(sheetThrottleLimit <= 0 || ctx.SheetCount <= sheetThrottleLimit,
374364
"sheet count exceeds throttle limit");
375-
Debug.Assert(catThrottleLimit <= 0 || catCount <= catThrottleLimit,
365+
Debug.Assert(catThrottleLimit <= 0 || ctx.CategoryCount <= catThrottleLimit,
376366
"category count exceeds throttle limit");
377-
Debug.Assert(globalThrottleLimit <= 0 || globalCount <= globalThrottleLimit,
367+
Debug.Assert(globalThrottleLimit <= 0 || ctx.GlobalCount <= globalThrottleLimit,
378368
"global count exceeds throttle limit");
379369
#endif
380370

381371
// Phase 1: Resolve eviction candidates per scope without executing.
382-
// AdjustCountsAfterEviction updates local counts so subsequent scopes
383-
// see the effect of prior evictions. Actual stop is deferred to Phase 2
384-
// to ensure no side effects when a later scope rejects the play.
385-
if (!ThrottleResolver.ResolveThrottle(cueThrottleType, cueThrottleLimit,
386-
cueCount, cueMin, track.priority, cueOldest,
387-
out var cueEviction))
372+
// Resolve* updates counts so subsequent scopes see the effect of prior evictions.
373+
// Actual stop is deferred to Phase 2 to ensure no side effects when a later scope rejects.
374+
if (!ctx.ResolveCue(cueThrottleType, cueThrottleLimit, track.priority, out var cueEviction))
388375
return false;
389-
ThrottleResolver.AdjustCountsAfterEviction(cueEviction, cueSheetId, cue, cue.categoryId,
390-
ref cueCount, ref sheetCount, ref catCount, ref globalCount);
391376

392-
if (!ThrottleResolver.ResolveThrottle(sheetThrottleType, sheetThrottleLimit,
393-
sheetCount, sheetMin, track.priority, sheetOldest,
394-
out var sheetEviction))
377+
if (!ctx.ResolveSheet(sheetThrottleType, sheetThrottleLimit, track.priority, out var sheetEviction))
395378
return false;
396-
ThrottleResolver.AdjustCountsAfterEviction(sheetEviction, cueSheetId, cue, cue.categoryId,
397-
ref cueCount, ref sheetCount, ref catCount, ref globalCount);
398379

399-
if (!ThrottleResolver.ResolveThrottle(catThrottleType, catThrottleLimit,
400-
catCount, catMin, track.priority, catOldest,
401-
out var catEviction))
380+
if (!ctx.ResolveCategory(catThrottleType, catThrottleLimit, track.priority, out var catEviction))
402381
return false;
403-
ThrottleResolver.AdjustCountsAfterEviction(catEviction, cueSheetId, cue, cue.categoryId,
404-
ref cueCount, ref sheetCount, ref catCount, ref globalCount);
405382

406-
if (!ThrottleResolver.ResolveThrottle(globalThrottleType, globalThrottleLimit,
407-
globalCount, globalMin, track.priority, globalOldest,
408-
out var globalEviction))
383+
if (!ctx.ResolveGlobal(globalThrottleType, globalThrottleLimit, track.priority, out var globalEviction))
409384
return false;
410385

411386
// Phase 2: All scopes passed — execute deferred evictions.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// --------------------------------------------------------------
2+
// Copyright 2026 CyberAgent, Inc.
3+
// --------------------------------------------------------------
4+
5+
#nullable enable
6+
7+
using AudioConductor.Core.Enums;
8+
using AudioConductor.Core.Models;
9+
using static AudioConductor.Core.Conductor;
10+
11+
namespace AudioConductor.Core
12+
{
13+
internal ref struct ThrottleContext
14+
{
15+
private readonly uint _targetCueSheetId;
16+
private readonly Cue _targetCue;
17+
private readonly int _targetCategoryId;
18+
19+
private ThrottleScopeState _cue;
20+
private ThrottleScopeState _sheet;
21+
private ThrottleScopeState _category;
22+
private ThrottleScopeState _global;
23+
24+
internal int CueCount => _cue.Count;
25+
internal int SheetCount => _sheet.Count;
26+
internal int CategoryCount => _category.Count;
27+
internal int GlobalCount => _global.Count;
28+
29+
internal ThrottleContext(uint cueSheetId, Cue cue)
30+
{
31+
_targetCueSheetId = cueSheetId;
32+
_targetCue = cue;
33+
_targetCategoryId = cue.categoryId;
34+
_cue = default;
35+
_sheet = default;
36+
_category = default;
37+
_global = default;
38+
}
39+
40+
internal void Accumulate(in Playback p)
41+
{
42+
if (p.Player.State == PlayerState.Stopped)
43+
return;
44+
_global.Accumulate(in p);
45+
if (BelongsToSheet(in p)) _sheet.Accumulate(in p);
46+
if (BelongsToCue(in p)) _cue.Accumulate(in p);
47+
if (BelongsToCategory(in p)) _category.Accumulate(in p);
48+
}
49+
50+
internal void AdjustAfterEviction(Playback? eviction)
51+
{
52+
if (!eviction.HasValue)
53+
return;
54+
var e = eviction.Value;
55+
_global.Decrement();
56+
if (BelongsToSheet(in e)) _sheet.Decrement();
57+
if (BelongsToCue(in e)) _cue.Decrement();
58+
if (BelongsToCategory(in e)) _category.Decrement();
59+
}
60+
61+
internal bool ResolveCue(ThrottleType type, int limit, int incomingPriority, out Playback? eviction)
62+
{
63+
if (!_cue.Resolve(type, limit, incomingPriority, out eviction))
64+
return false;
65+
AdjustAfterEviction(eviction);
66+
return true;
67+
}
68+
69+
internal bool ResolveSheet(ThrottleType type, int limit, int incomingPriority, out Playback? eviction)
70+
{
71+
if (!_sheet.Resolve(type, limit, incomingPriority, out eviction))
72+
return false;
73+
AdjustAfterEviction(eviction);
74+
return true;
75+
}
76+
77+
internal bool ResolveCategory(ThrottleType type, int limit, int incomingPriority, out Playback? eviction)
78+
{
79+
if (!_category.Resolve(type, limit, incomingPriority, out eviction))
80+
return false;
81+
AdjustAfterEviction(eviction);
82+
return true;
83+
}
84+
85+
internal bool ResolveGlobal(ThrottleType type, int limit, int incomingPriority, out Playback? eviction)
86+
{
87+
if (!_global.Resolve(type, limit, incomingPriority, out eviction))
88+
return false;
89+
AdjustAfterEviction(eviction);
90+
return true;
91+
}
92+
93+
private readonly bool BelongsToSheet(in Playback p)
94+
{
95+
return p.CueSheetId == _targetCueSheetId;
96+
}
97+
98+
private readonly bool BelongsToCue(in Playback p)
99+
{
100+
return p.Cue == _targetCue;
101+
}
102+
103+
private readonly bool BelongsToCategory(in Playback p)
104+
{
105+
return p.Cue.categoryId == _targetCategoryId;
106+
}
107+
}
108+
}

Packages/AudioConductor/Runtime/Core/ThrottleResolver.cs.meta renamed to Packages/AudioConductor/Runtime/Core/ThrottleContext.cs.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)