Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and releases follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Streaming PCM analysis through `MusaveraStreamingSession`, including
realtime loudness results and final aggregate analysis.

## 0.1.0 - 2026-06-13

### Added
Expand Down
69 changes: 67 additions & 2 deletions Examples/MusaveraLab/MusaveraLab.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,63 @@
objects = {

/* Begin PBXBuildFile section */
21DA8B957D4C23AF4896CB30 /* LiveStreamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773251A88F78F71EF655F53F /* LiveStreamView.swift */; };
24785B8BAB77C0EBC9A28DA1 /* MusaveraLabModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E038E4851D68CBE647F8DF98 /* MusaveraLabModel.swift */; };
2AD8EE2019F19C3DC7536C8E /* MusicBrowserSidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5DD336EA101AD39E6141936 /* MusicBrowserSidebar.swift */; };
2BA84BC4C0402FADE8E84A6F /* MusaveraLabApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0BE121349F66D59ED4BD2A /* MusaveraLabApp.swift */; };
4E9EB78FBA07F3AED856D197 /* AnalysisDashboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72FE5CB39CDA7B494D1DE3A4 /* AnalysisDashboard.swift */; };
50E590E35281E47FBB31B57A /* MusicSelectionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2965F30D5C9A008DC2AFD30 /* MusicSelectionSheet.swift */; };
68E36C0E62FDBAC2EF3DF7F3 /* LiveStreamError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF70B3C1E29572AE441DE534 /* LiveStreamError.swift */; };
6E85767F9490B545C1D4EF21 /* AnalysisResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCFA482A340B55F54FCF30BC /* AnalysisResultsView.swift */; };
740A41F026B23CD3EC530064 /* LiveLoudnessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F4B8CF7D3D8C20A2C53792E /* LiveLoudnessView.swift */; };
7B604FAF786BE94A91F85BE3 /* LabSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F57F6E67F40B939D10D2B323 /* LabSection.swift */; };
8C37156321C220D60A4BB470 /* Musavera Lab.icon in Resources */ = {isa = PBXBuildFile; fileRef = 8647D544CED10403821B344A /* Musavera Lab.icon */; };
A02CD915DDE930A7BF199CB3 /* LiveStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 701E55CEC44C91AC4EB8A3E9 /* LiveStreamHeader.swift */; };
A7BDBEE7E6AF9943011DA9F2 /* LiveFinalAnalysisView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4496F1324C2312872AC5DA68 /* LiveFinalAnalysisView.swift */; };
A81A422116DAC9B8A6125471 /* PreviewPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3D4276646810C2DA45A3E8 /* PreviewPlayer.swift */; };
A91B6A70C878816A79A7C3AF /* AnalysisJSONDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7DEA2C229BDA2A4B85CAAA /* AnalysisJSONDocument.swift */; };
B0F5DFB080DD500DF9A8B5FF /* AnalysisComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28134147038B1E3872648893 /* AnalysisComponents.swift */; };
C244F797E1A8335CF09C3A8D /* LiveRecordingTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33290F119D182479F1D5DBC /* LiveRecordingTransport.swift */; };
C533DF268C534BC55CE1EB65 /* AnalyzeWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45240A93A424DC0458B95A59 /* AnalyzeWelcomeView.swift */; };
CC1D83FF672A25C9BFC2D5C9 /* LiveStreamModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9563903791411B1D985ED35 /* LiveStreamModel.swift */; };
D55BBD16F76645103279A0DC /* TimelineComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92C546425026A586D4AE6F60 /* TimelineComponents.swift */; };
E3553AC3D8690FBDCEC66F53 /* MusaveraKit in Frameworks */ = {isa = PBXBuildFile; productRef = 79D134AB9DE2AC7ECDA156A9 /* MusaveraKit */; };
E9A96DD35B7FDEF43189AA2A /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F91F1BF6C6D59CC92807B9 /* Theme.swift */; };
EC67369138AEA5397F184A95 /* AudioFileStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A018FE4324BF125ABD274B2D /* AudioFileStore.swift */; };
F0D97C334B4F79CA294898F9 /* TransportBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ECFFBEFCF66FA2E2FAB48D /* TransportBar.swift */; };
F17FAD96862797EAC998B10D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D7010759E3CE72A46D76413 /* ContentView.swift */; };
F702E58D57C0246CCFE6821C /* LiveStreamState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C40DF98E80114E1B6B9D39 /* LiveStreamState.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
16850E396168613A82B4E05D /* MusaveraLab.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MusaveraLab.app; sourceTree = BUILT_PRODUCTS_DIR; };
17C40DF98E80114E1B6B9D39 /* LiveStreamState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamState.swift; sourceTree = "<group>"; };
17F91F1BF6C6D59CC92807B9 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
28134147038B1E3872648893 /* AnalysisComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalysisComponents.swift; sourceTree = "<group>"; };
351EE86AE67DD541E20901CC /* MusaveraLab.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MusaveraLab.entitlements; sourceTree = "<group>"; };
4496F1324C2312872AC5DA68 /* LiveFinalAnalysisView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveFinalAnalysisView.swift; sourceTree = "<group>"; };
45240A93A424DC0458B95A59 /* AnalyzeWelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyzeWelcomeView.swift; sourceTree = "<group>"; };
4B3D4276646810C2DA45A3E8 /* PreviewPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewPlayer.swift; sourceTree = "<group>"; };
5D7010759E3CE72A46D76413 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
6D0BE121349F66D59ED4BD2A /* MusaveraLabApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusaveraLabApp.swift; sourceTree = "<group>"; };
701E55CEC44C91AC4EB8A3E9 /* LiveStreamHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamHeader.swift; sourceTree = "<group>"; };
72FE5CB39CDA7B494D1DE3A4 /* AnalysisDashboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalysisDashboard.swift; sourceTree = "<group>"; };
773251A88F78F71EF655F53F /* LiveStreamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamView.swift; sourceTree = "<group>"; };
7F4B8CF7D3D8C20A2C53792E /* LiveLoudnessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLoudnessView.swift; sourceTree = "<group>"; };
8647D544CED10403821B344A /* Musavera Lab.icon */ = {isa = PBXFileReference; lastKnownFileType = wrapper.icon; path = "Musavera Lab.icon"; sourceTree = "<group>"; };
92C546425026A586D4AE6F60 /* TimelineComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineComponents.swift; sourceTree = "<group>"; };
A018FE4324BF125ABD274B2D /* AudioFileStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioFileStore.swift; sourceTree = "<group>"; };
B6ECFFBEFCF66FA2E2FAB48D /* TransportBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransportBar.swift; sourceTree = "<group>"; };
BF70B3C1E29572AE441DE534 /* LiveStreamError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamError.swift; sourceTree = "<group>"; };
C5DD336EA101AD39E6141936 /* MusicBrowserSidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicBrowserSidebar.swift; sourceTree = "<group>"; };
C9563903791411B1D985ED35 /* LiveStreamModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveStreamModel.swift; sourceTree = "<group>"; };
CCFA482A340B55F54FCF30BC /* AnalysisResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalysisResultsView.swift; sourceTree = "<group>"; };
D33290F119D182479F1D5DBC /* LiveRecordingTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveRecordingTransport.swift; sourceTree = "<group>"; };
DBF41C8160D78F589E34CEE8 /* MusaveraKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = MusaveraKit; path = ../..; sourceTree = SOURCE_ROOT; };
DE7DEA2C229BDA2A4B85CAAA /* AnalysisJSONDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalysisJSONDocument.swift; sourceTree = "<group>"; };
E038E4851D68CBE647F8DF98 /* MusaveraLabModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusaveraLabModel.swift; sourceTree = "<group>"; };
E2965F30D5C9A008DC2AFD30 /* MusicSelectionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicSelectionSheet.swift; sourceTree = "<group>"; };
F57F6E67F40B939D10D2B323 /* LabSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabSection.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -67,7 +91,14 @@
children = (
28134147038B1E3872648893 /* AnalysisComponents.swift */,
72FE5CB39CDA7B494D1DE3A4 /* AnalysisDashboard.swift */,
CCFA482A340B55F54FCF30BC /* AnalysisResultsView.swift */,
45240A93A424DC0458B95A59 /* AnalyzeWelcomeView.swift */,
5D7010759E3CE72A46D76413 /* ContentView.swift */,
4496F1324C2312872AC5DA68 /* LiveFinalAnalysisView.swift */,
7F4B8CF7D3D8C20A2C53792E /* LiveLoudnessView.swift */,
D33290F119D182479F1D5DBC /* LiveRecordingTransport.swift */,
701E55CEC44C91AC4EB8A3E9 /* LiveStreamHeader.swift */,
773251A88F78F71EF655F53F /* LiveStreamView.swift */,
C5DD336EA101AD39E6141936 /* MusicBrowserSidebar.swift */,
E2965F30D5C9A008DC2AFD30 /* MusicSelectionSheet.swift */,
B6ECFFBEFCF66FA2E2FAB48D /* TransportBar.swift */,
Expand All @@ -88,6 +119,9 @@
isa = PBXGroup;
children = (
A018FE4324BF125ABD274B2D /* AudioFileStore.swift */,
BF70B3C1E29572AE441DE534 /* LiveStreamError.swift */,
C9563903791411B1D985ED35 /* LiveStreamModel.swift */,
17C40DF98E80114E1B6B9D39 /* LiveStreamState.swift */,
4B3D4276646810C2DA45A3E8 /* PreviewPlayer.swift */,
);
path = Services;
Expand All @@ -112,6 +146,7 @@
9F3BF4EA07744FF279BBA3D0 /* App */ = {
isa = PBXGroup;
children = (
F57F6E67F40B939D10D2B323 /* LabSection.swift */,
6D0BE121349F66D59ED4BD2A /* MusaveraLabApp.swift */,
E038E4851D68CBE647F8DF98 /* MusaveraLabModel.swift */,
);
Expand All @@ -121,6 +156,7 @@
CD691D72EA74C87BF3D616F5 /* MusaveraLab */ = {
isa = PBXGroup;
children = (
8647D544CED10403821B344A /* Musavera Lab.icon */,
351EE86AE67DD541E20901CC /* MusaveraLab.entitlements */,
17F91F1BF6C6D59CC92807B9 /* Theme.swift */,
9F3BF4EA07744FF279BBA3D0 /* App */,
Expand Down Expand Up @@ -148,6 +184,7 @@
buildConfigurationList = 4A95BEC55B4F4C2577B13035 /* Build configuration list for PBXNativeTarget "MusaveraLab" */;
buildPhases = (
CE074CFB82092D3783CAFD50 /* Sources */,
E486B4177EC2EDE90291A53F /* Resources */,
977874206CB93E56BD73BA4D /* Frameworks */,
);
buildRules = (
Expand Down Expand Up @@ -199,6 +236,17 @@
};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
E486B4177EC2EDE90291A53F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C37156321C220D60A4BB470 /* Musavera Lab.icon in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
CE074CFB82092D3783CAFD50 /* Sources */ = {
isa = PBXSourcesBuildPhase;
Expand All @@ -207,8 +255,19 @@
B0F5DFB080DD500DF9A8B5FF /* AnalysisComponents.swift in Sources */,
4E9EB78FBA07F3AED856D197 /* AnalysisDashboard.swift in Sources */,
A91B6A70C878816A79A7C3AF /* AnalysisJSONDocument.swift in Sources */,
6E85767F9490B545C1D4EF21 /* AnalysisResultsView.swift in Sources */,
C533DF268C534BC55CE1EB65 /* AnalyzeWelcomeView.swift in Sources */,
EC67369138AEA5397F184A95 /* AudioFileStore.swift in Sources */,
F17FAD96862797EAC998B10D /* ContentView.swift in Sources */,
7B604FAF786BE94A91F85BE3 /* LabSection.swift in Sources */,
A7BDBEE7E6AF9943011DA9F2 /* LiveFinalAnalysisView.swift in Sources */,
740A41F026B23CD3EC530064 /* LiveLoudnessView.swift in Sources */,
C244F797E1A8335CF09C3A8D /* LiveRecordingTransport.swift in Sources */,
68E36C0E62FDBAC2EF3DF7F3 /* LiveStreamError.swift in Sources */,
A02CD915DDE930A7BF199CB3 /* LiveStreamHeader.swift in Sources */,
CC1D83FF672A25C9BFC2D5C9 /* LiveStreamModel.swift in Sources */,
F702E58D57C0246CCFE6821C /* LiveStreamState.swift in Sources */,
21DA8B957D4C23AF4896CB30 /* LiveStreamView.swift in Sources */,
2BA84BC4C0402FADE8E84A6F /* MusaveraLabApp.swift in Sources */,
24785B8BAB77C0EBC9A28DA1 /* MusaveraLabModel.swift in Sources */,
2AD8EE2019F19C3DC7536C8E /* MusicBrowserSidebar.swift in Sources */,
Expand Down Expand Up @@ -294,12 +353,14 @@
BA6F66BD215783BC54571F70 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_APPICON_NAME = "Musavera Lab";
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = MusaveraLab/MusaveraLab.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_APP_SANDBOX = YES;
ENABLE_AUDIO_INPUT = YES;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
ENABLE_PREVIEWS = YES;
Expand All @@ -308,6 +369,7 @@
INFOPLIST_KEY_CFBundleDisplayName = "Musavera Lab";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
INFOPLIST_KEY_NSAppleMusicUsageDescription = "Musavera Lab uses Apple Music to search the catalog and play songs you choose.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Musavera Lab uses the microphone to analyze live audio on this Mac.";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
Expand All @@ -322,12 +384,14 @@
DC3D19AEF2B3314DB1BCCF7D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_APPICON_NAME = "Musavera Lab";
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = MusaveraLab/MusaveraLab.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_APP_SANDBOX = YES;
ENABLE_AUDIO_INPUT = YES;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
ENABLE_PREVIEWS = YES;
Expand All @@ -336,6 +400,7 @@
INFOPLIST_KEY_CFBundleDisplayName = "Musavera Lab";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
INFOPLIST_KEY_NSAppleMusicUsageDescription = "Musavera Lab uses Apple Music to search the catalog and play songs you choose.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Musavera Lab uses the microphone to analyze live audio on this Mac.";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
Expand Down
35 changes: 35 additions & 0 deletions Examples/MusaveraLab/MusaveraLab/App/LabSection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import SwiftUI

enum LabSection: String, CaseIterable, Identifiable {
case analyze
case live

var id: Self { self }

var title: String {
switch self {
case .analyze:
"Analyze Music"
case .live:
"Live Stream"
}
}

var subtitle: String {
switch self {
case .analyze:
"Apple Music previews and audio files"
case .live:
"Microphone loudness and final analysis"
}
}

var systemImage: String {
switch self {
case .analyze:
"waveform.path.ecg"
case .live:
"waveform.badge.microphone"
}
}
}
4 changes: 4 additions & 0 deletions Examples/MusaveraLab/MusaveraLab/App/MusaveraLabApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import SwiftUI
@main
struct MusaveraLabApp: App {
@State private var model = MusaveraLabModel()
@State private var liveStreamModel = LiveStreamModel()

var body: some Scene {
WindowGroup {
ContentView()
.environment(model)
.environment(liveStreamModel)
.environment(model.previewPlayer)
.tint(LabTheme.accent)
.frame(minWidth: 1_080, minHeight: 720)
}
.defaultSize(width: 1_320, height: 860)
.windowToolbarStyle(.unifiedCompact(showsTitle: false))
}
}
14 changes: 11 additions & 3 deletions Examples/MusaveraLab/MusaveraLab/App/MusaveraLabModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,19 @@ final class MusaveraLabModel {
var analysis: MusaveraAnalysis?
var workState: WorkState = .idle
var errorMessage: String?
private(set) var fullSongPlaybackStatus = ApplicationMusicPlayer.shared.state.playbackStatus
private(set) var fullSongPlaybackStatus: MusicKit.MusicPlayer.PlaybackStatus = .stopped
private(set) var isStartingFullSong = false

let previewPlayer = PreviewPlayer()

@ObservationIgnored private let fileStore = AudioFileStore()
@ObservationIgnored private let fullSongPlayer = ApplicationMusicPlayer.shared
@ObservationIgnored private let fullSongState = ApplicationMusicPlayer.shared.state
@ObservationIgnored private var fullSongStateTask: Task<Void, Never>?
@ObservationIgnored private var pendingFullSongPlayID: UUID?

init() {
fullSongPlaybackStatus = fullSongState.playbackStatus
observeFullSongState()
}

Expand Down Expand Up @@ -203,6 +205,7 @@ final class MusaveraLabModel {
do {
fullSongPlayer.queue = ApplicationMusicPlayer.Queue(for: [selectedSong])
try await fullSongPlayer.play()
fullSongPlaybackStatus = fullSongState.playbackStatus
guard pendingFullSongPlayID == requestID else {
fullSongPlayer.pause()
return
Expand All @@ -213,6 +216,11 @@ final class MusaveraLabModel {
}
}

func pauseAllPlayback() {
previewPlayer.pause()
cancelFullSongPlayback()
}

func reset() {
previewPlayer.unload()
cancelFullSongPlayback()
Expand Down Expand Up @@ -291,10 +299,10 @@ final class MusaveraLabModel {
}

private func observeFullSongState() {
let player = fullSongPlayer
let state = fullSongState
fullSongStateTask = Task { @MainActor [weak self] in
let statuses = Observations {
player.state.playbackStatus
state.playbackStatus
}

for await status in statuses {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions Examples/MusaveraLab/MusaveraLab/Musavera Lab.icon/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"fill" : {
"automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
},
"groups" : [
{
"layers" : [
{
"image-name" : "Musavera-Lab-Icon-1024.png",
"name" : "Musavera Mark"
}
],
"name" : "Artwork",
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : false,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}
2 changes: 2 additions & 0 deletions Examples/MusaveraLab/MusaveraLab/MusaveraLab.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
Expand Down
Loading