Refactor feedback sample playback logic

This commit is contained in:
Jamie Taylor 2022-08-31 17:21:58 +09:00
parent 6cadcc206b
commit cc9dc604a0
No known key found for this signature in database
GPG Key ID: 2ACFA8B6370B8C8C

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
@ -40,30 +42,26 @@ namespace osu.Game.Graphics.UserInterface
Margin = new MarginPadding { Left = 2 }, Margin = new MarginPadding { Left = 2 },
}; };
private readonly Sample?[] textAddedSamples = new Sample[4];
private Sample? capsTextAddedSample;
private Sample? textRemovedSample;
private Sample? textCommittedSample;
private Sample? caretMovedSample;
private Sample? selectCharSample;
private Sample? selectWordSample;
private Sample? selectAllSample;
private Sample? deselectSample;
private OsuCaret? caret; private OsuCaret? caret;
private bool selectionStarted; private bool selectionStarted;
private double sampleLastPlaybackTime; private double sampleLastPlaybackTime;
private enum SelectionSampleType private enum FeedbackSampleType
{ {
Character, TextAdd,
Word, TextAddCaps,
All, TextRemove,
TextConfirm,
CaretMove,
SelectCharacter,
SelectWord,
SelectAll,
Deselect Deselect
} }
private Dictionary<FeedbackSampleType, Sample?[]> sampleMap = new Dictionary<FeedbackSampleType, Sample?[]>();
public OsuTextBox() public OsuTextBox()
{ {
Height = 40; Height = 40;
@ -87,18 +85,22 @@ namespace osu.Game.Graphics.UserInterface
Placeholder.Colour = colourProvider?.Foreground1 ?? new Color4(180, 180, 180, 255); Placeholder.Colour = colourProvider?.Foreground1 ?? new Color4(180, 180, 180, 255);
var textAddedSamples = new Sample?[4];
for (int i = 0; i < textAddedSamples.Length; i++) for (int i = 0; i < textAddedSamples.Length; i++)
textAddedSamples[i] = audio.Samples.Get($@"Keyboard/key-press-{1 + i}"); textAddedSamples[i] = audio.Samples.Get($@"Keyboard/key-press-{1 + i}");
capsTextAddedSample = audio.Samples.Get(@"Keyboard/key-caps"); sampleMap = new Dictionary<FeedbackSampleType, Sample?[]>
textRemovedSample = audio.Samples.Get(@"Keyboard/key-delete"); {
textCommittedSample = audio.Samples.Get(@"Keyboard/key-confirm"); { FeedbackSampleType.TextAdd, textAddedSamples },
caretMovedSample = audio.Samples.Get(@"Keyboard/key-movement"); { FeedbackSampleType.TextAddCaps, new[] { audio.Samples.Get(@"Keyboard/key-caps") } },
{ FeedbackSampleType.TextRemove, new[] { audio.Samples.Get(@"Keyboard/key-delete") } },
selectCharSample = audio.Samples.Get(@"Keyboard/select-char"); { FeedbackSampleType.TextConfirm, new[] { audio.Samples.Get(@"Keyboard/key-confirm") } },
selectWordSample = audio.Samples.Get(@"Keyboard/select-word"); { FeedbackSampleType.CaretMove, new[] { audio.Samples.Get(@"Keyboard/key-movement") } },
selectAllSample = audio.Samples.Get(@"Keyboard/select-all"); { FeedbackSampleType.SelectCharacter, new[] { audio.Samples.Get(@"Keyboard/select-char") } },
deselectSample = audio.Samples.Get(@"Keyboard/deselect"); { FeedbackSampleType.SelectWord, new[] { audio.Samples.Get(@"Keyboard/select-word") } },
{ FeedbackSampleType.SelectAll, new[] { audio.Samples.Get(@"Keyboard/select-all") } },
{ FeedbackSampleType.Deselect, new[] { audio.Samples.Get(@"Keyboard/deselect") } }
};
} }
private Color4 selectionColour; private Color4 selectionColour;
@ -110,23 +112,23 @@ namespace osu.Game.Graphics.UserInterface
base.OnUserTextAdded(added); base.OnUserTextAdded(added);
if (added.Any(char.IsUpper) && AllowUniqueCharacterSamples) if (added.Any(char.IsUpper) && AllowUniqueCharacterSamples)
capsTextAddedSample?.Play(); playSample(FeedbackSampleType.TextAddCaps);
else else
playTextAddedSample(); playSample(FeedbackSampleType.TextAdd);
} }
protected override void OnUserTextRemoved(string removed) protected override void OnUserTextRemoved(string removed)
{ {
base.OnUserTextRemoved(removed); base.OnUserTextRemoved(removed);
textRemovedSample?.Play(); playSample(FeedbackSampleType.TextRemove);
} }
protected override void OnTextCommitted(bool textChanged) protected override void OnTextCommitted(bool textChanged)
{ {
base.OnTextCommitted(textChanged); base.OnTextCommitted(textChanged);
textCommittedSample?.Play(); playSample(FeedbackSampleType.TextConfirm);
} }
protected override void OnCaretMoved(bool selecting) protected override void OnCaretMoved(bool selecting)
@ -134,7 +136,7 @@ namespace osu.Game.Graphics.UserInterface
base.OnCaretMoved(selecting); base.OnCaretMoved(selecting);
if (!selecting) if (!selecting)
caretMovedSample?.Play(); playSample(FeedbackSampleType.CaretMove);
} }
protected override void OnTextSelectionChanged(TextSelectionType selectionType) protected override void OnTextSelectionChanged(TextSelectionType selectionType)
@ -144,15 +146,15 @@ namespace osu.Game.Graphics.UserInterface
switch (selectionType) switch (selectionType)
{ {
case TextSelectionType.Character: case TextSelectionType.Character:
playSelectSample(SelectionSampleType.Character); playSample(FeedbackSampleType.SelectCharacter);
break; break;
case TextSelectionType.Word: case TextSelectionType.Word:
playSelectSample(selectionStarted ? SelectionSampleType.Character : SelectionSampleType.Word); playSample(selectionStarted ? FeedbackSampleType.SelectCharacter : FeedbackSampleType.SelectWord);
break; break;
case TextSelectionType.All: case TextSelectionType.All:
playSelectSample(SelectionSampleType.All); playSample(FeedbackSampleType.SelectAll);
break; break;
} }
@ -165,7 +167,7 @@ namespace osu.Game.Graphics.UserInterface
if (!selectionStarted) return; if (!selectionStarted) return;
playSelectSample(SelectionSampleType.Deselect); playSample(FeedbackSampleType.Deselect);
selectionStarted = false; selectionStarted = false;
} }
@ -184,13 +186,13 @@ namespace osu.Game.Graphics.UserInterface
case 1: case 1:
// composition probably ended by pressing backspace, or was cancelled. // composition probably ended by pressing backspace, or was cancelled.
textRemovedSample?.Play(); playSample(FeedbackSampleType.TextRemove);
return; return;
default: default:
// longer text removed, composition ended because it was cancelled. // longer text removed, composition ended because it was cancelled.
// could be a different sample if desired. // could be a different sample if desired.
textRemovedSample?.Play(); playSample(FeedbackSampleType.TextRemove);
return; return;
} }
} }
@ -198,7 +200,7 @@ namespace osu.Game.Graphics.UserInterface
if (addedTextLength > 0) if (addedTextLength > 0)
{ {
// some text was added, probably due to typing new text or by changing the candidate. // some text was added, probably due to typing new text or by changing the candidate.
playTextAddedSample(); playSample(FeedbackSampleType.TextAdd);
return; return;
} }
@ -206,14 +208,14 @@ namespace osu.Game.Graphics.UserInterface
{ {
// text was probably removed by backspacing. // text was probably removed by backspacing.
// it's also possible that a candidate that only removed text was changed to. // it's also possible that a candidate that only removed text was changed to.
textRemovedSample?.Play(); playSample(FeedbackSampleType.TextRemove);
return; return;
} }
if (caretMoved) if (caretMoved)
{ {
// only the caret/selection was moved. // only the caret/selection was moved.
caretMovedSample?.Play(); playSample(FeedbackSampleType.CaretMove);
} }
} }
@ -224,13 +226,13 @@ namespace osu.Game.Graphics.UserInterface
if (successful) if (successful)
{ {
// composition was successfully completed, usually by pressing the enter key. // composition was successfully completed, usually by pressing the enter key.
textCommittedSample?.Play(); playSample(FeedbackSampleType.TextConfirm);
} }
else else
{ {
// composition was prematurely ended, eg. by clicking inside the textbox. // composition was prematurely ended, eg. by clicking inside the textbox.
// could be a different sample if desired. // could be a different sample if desired.
textCommittedSample?.Play(); playSample(FeedbackSampleType.TextConfirm);
} }
} }
@ -259,43 +261,35 @@ namespace osu.Game.Graphics.UserInterface
SelectionColour = SelectionColour, SelectionColour = SelectionColour,
}; };
private void playSelectSample(SelectionSampleType selectionType) private SampleChannel? getSampleChannel(FeedbackSampleType feedbackSampleType)
{
var samples = sampleMap[feedbackSampleType];
if (samples == null || samples.Length == 0)
return null;
return samples[RNG.Next(0, samples.Length)]?.GetChannel();
}
private void playSample(FeedbackSampleType feedbackSample)
{ {
if (Time.Current < sampleLastPlaybackTime + 15) return; if (Time.Current < sampleLastPlaybackTime + 15) return;
SampleChannel? channel; SampleChannel? channel = getSampleChannel(feedbackSample);
double pitch = 0.98 + RNG.NextDouble(0.04);
switch (selectionType)
{
case SelectionSampleType.All:
channel = selectAllSample?.GetChannel();
break;
case SelectionSampleType.Word:
channel = selectWordSample?.GetChannel();
break;
case SelectionSampleType.Deselect:
channel = deselectSample?.GetChannel();
break;
default:
channel = selectCharSample?.GetChannel();
pitch += (SelectedText.Length / (double)Text.Length) * 0.15f;
break;
}
if (channel == null) return; if (channel == null) return;
double pitch = 0.98 + RNG.NextDouble(0.04);
if (feedbackSample == FeedbackSampleType.SelectCharacter)
pitch += ((double)SelectedText.Length / Math.Max(1, Text.Length)) * 0.15f;
channel.Frequency.Value = pitch; channel.Frequency.Value = pitch;
channel.Play(); channel.Play();
sampleLastPlaybackTime = Time.Current; sampleLastPlaybackTime = Time.Current;
} }
private void playTextAddedSample() => textAddedSamples[RNG.Next(0, textAddedSamples.Length)]?.Play();
private class OsuCaret : Caret private class OsuCaret : Caret
{ {
private const float caret_move_time = 60; private const float caret_move_time = 60;