private void trackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction = TrackChangeDirection.None) { // avoid using scheduler as our scheduler may not be run for a long time, holding references to beatmaps. pendingBeatmapSwitch = delegate { // todo: this can likely be replaced with WorkingBeatmap.GetBeatmapAsync() Task.Run(() => { if (beatmap?.Beatmap == null) // this is not needed if a placeholder exists { title.Text = @"Nothing to play"; artist.Text = @"Nothing to play"; } else { BeatmapMetadata metadata = beatmap.Metadata; title.Text = new RomanisableString(metadata.TitleUnicode, metadata.Title); artist.Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); } }); LoadComponentAsync(new Background(beatmap) { Depth = float.MaxValue }, newBackground => { switch (direction) { case TrackChangeDirection.Next: newBackground.Position = new Vector2(400, 0); newBackground.MoveToX(0, 500, Easing.OutCubic); background.MoveToX(-400, 500, Easing.OutCubic); break; case TrackChangeDirection.Prev: newBackground.Position = new Vector2(-400, 0); newBackground.MoveToX(0, 500, Easing.OutCubic); background.MoveToX(400, 500, Easing.OutCubic); break; } background.Expire(); background = newBackground; playerContainer.Add(newBackground); }); }; }
private void trackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction = TrackChangeDirection.None) { pendingBeatmapSwitch = () => { Task.Run(() => { if (beatmap?.Beatmap == null) { nowPlayingInfo.Title = DrawableNowPlayingInfo.NULL_TITLE; nowPlayingInfo.Artist = DrawableNowPlayingInfo.NULL_TITLE; nowPlayingInfo.Source = DrawableNowPlayingInfo.NULL_SOURCE; } else { BeatmapMetadata metadata = beatmap.Metadata; nowPlayingInfo.Title = new RomanisableString(metadata.TitleUnicode, metadata.Title); nowPlayingInfo.Artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); nowPlayingInfo.Source = new RomanisableString(metadata.Source, null); } }); }; }
private void changeBeatmap(WorkingBeatmap newWorking) { // This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order // (changeBeatmap must be called before consumers receive the bindable changed event, which is not the case when the local beatmap bindable is updated directly). if (newWorking == current) { return; } var lastWorking = current; TrackChangeDirection direction = TrackChangeDirection.None; bool audioEquals = newWorking?.BeatmapInfo?.AudioEquals(current?.BeatmapInfo) ?? false; if (current != null) { if (audioEquals) { direction = TrackChangeDirection.None; } else if (queuedDirection.HasValue) { direction = queuedDirection.Value; queuedDirection = null; } else { // figure out the best direction based on order in playlist. var last = BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count(); var next = newWorking == null ? -1 : BeatmapSets.TakeWhile(b => b.ID != newWorking.BeatmapSetInfo?.ID).Count(); direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next; } } current = newWorking; if (!audioEquals || CurrentTrack.IsDummyDevice) { changeTrack(); } else { // transfer still valid track to new working beatmap current.TransferTrack(lastWorking.Track); } TrackChanged?.Invoke(current, direction); ResetTrackAdjustments(); queuedDirection = null; // this will be a noop if coming from the beatmapChanged event. // the exception is local operations like next/prev, where we want to complete loading the track before sending out a change. if (beatmap.Value != current && beatmap is Bindable <WorkingBeatmap> working) { working.Value = current; } }
private void ensureTrackLooping(WorkingBeatmap beatmap, TrackChangeDirection changeDirection) => music.CurrentTrack.Looping = true;
private void onTrackChanged(WorkingBeatmap newBeatmap, TrackChangeDirection _) => updateStoryboardClockSource(newBeatmap);