Skip to content

Commit

Permalink
Merge pull request stakira#815 from maiko3tattun/0830_PasteParam
Browse files Browse the repository at this point in the history
Add "Select and paste parameters" and related methods
  • Loading branch information
stakira authored Sep 2, 2023
2 parents e041974 + ae9fa63 commit 3ed4bd4
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 38 deletions.
19 changes: 9 additions & 10 deletions OpenUtau.Core/Commands/ExpCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,23 @@ public ExpCommand(UVoicePart part) {
}
}

/*
public class SetNoteExpressionCommand : ExpCommand {
public readonly UProject project;
public readonly UPhoneme phoneme;
public readonly float newValue;
public readonly float oldValue;
public SetNoteExpressionCommand(UProject project, UNote note, string abbr, float value) {
public readonly UTrack track;
public readonly float[] newValue;
public readonly float[] oldValue;
public SetNoteExpressionCommand(UProject project, UTrack track, UVoicePart part, UNote note, string abbr, float[] values) : base(part) {
this.project = project;
this.track = track;
this.Note = note;
Key = abbr;
newValue = value;
oldValue = phoneme.GetExpression(project, abbr).Item1;
newValue = values;
oldValue = note.GetExpression(project, track, abbr).Select(t => t.Item1).ToArray();
}
public override string ToString() => $"Set note expression {Key}";
public override void Execute() => Note.SetExpression(project, Key, newValue);
public override void Unexecute() => Note.SetExpression(project, Key, oldValue);
public override void Execute() => Note.SetExpression(project, track, Key, newValue);
public override void Unexecute() => Note.SetExpression(project, track, Key, oldValue);
}
*/

public class SetPhonemeExpressionCommand : ExpCommand {
static readonly HashSet<string> needsPhonemizer = new HashSet<string> {
Expand Down
6 changes: 1 addition & 5 deletions OpenUtau.Core/Editing/LyricBatchEdits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,7 @@ public void Run(UProject project, UVoicePart part, List<UNote> selectedNotes, Do
docManager.ExecuteCmd(new ChangeNoteLyricCommand(part, note, lyric));

int index = colors.FirstOrDefault(c => c.Value == suffix).Key;
foreach (UPhoneme phoneme in part.phonemes) {
if (phoneme.Parent == note) {
docManager.ExecuteCmd(new SetPhonemeExpressionCommand(project, track, part, phoneme, Format.Ustx.CLR, index));
}
}
docManager.ExecuteCmd(new SetNoteExpressionCommand(project, track, part, note, Format.Ustx.CLR, new float[] { index }));
break;
}
}
Expand Down
6 changes: 5 additions & 1 deletion OpenUtau.Core/Editing/NoteBatchEdits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ public void Run(UProject project, UVoicePart part, List<UNote> selectedNotes, Do
var notes = selectedNotes.Count > 0 ? selectedNotes : part.notes.ToList();
foreach (var note in notes) {
if (note.lyric != lyric && (note.Next == null || note.Next.position > note.End + 120)) {
toAdd.Add(project.CreateNote(note.tone, note.End, 120));
var addNote = project.CreateNote(note.tone, note.End, 120);
foreach(var exp in note.phonemeExpressions.OrderBy(exp => exp.index)) {
addNote.SetExpression(project, project.tracks[part.trackNo], exp.abbr, new float[] { exp.value });
}
toAdd.Add(addNote);
}
}
if (toAdd.Count == 0) {
Expand Down
63 changes: 41 additions & 22 deletions OpenUtau.Core/Ustx/UNote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,34 +155,53 @@ public UPhonemeOverride GetPhonemeOverride(int index) {
return result;
}

/*
public float GetExpression(UProject project, string abbr) {
var descriptor = project.expressions[abbr];
Trace.Assert(descriptor.isNoteExpression);
var note = Extends ?? this;
var expression = note.noteExpressions.FirstOrDefault(exp => exp.descriptor == descriptor);
return expression == null ? expression.value : descriptor.defaultValue;
public List<Tuple<float, bool>> GetExpression(UProject project, UTrack track, string abbr) {
track.TryGetExpression(project, abbr, out var descriptor);
var list = new List<Tuple<float, bool>>();
int indexes = (phonemeExpressions.Max(exp => exp.index) ?? 0) + 1;

for (int i = 0; i < indexes; i++) {
var expression = phonemeExpressions.FirstOrDefault(exp => exp.descriptor?.abbr == descriptor.abbr && exp.index == i);
if (expression != null) {
list.Add(Tuple.Create(expression.value, true));
} else {
list.Add(Tuple.Create(descriptor.defaultValue, false));
}
}
return list;
}

public void SetExpression(UProject project, string abbr, float value) {
var descriptor = project.expressions[abbr];
Trace.Assert(descriptor.isNoteExpression);
var note = Extends ?? this;
if (value == descriptor.defaultValue) {
note.noteExpressions.RemoveAll(exp => exp.descriptor == descriptor);
public void SetExpression(UProject project, UTrack track, string abbr, float[] values) {
if (!track.TryGetExpression(project, abbr, out var descriptor)) {
return;
}
var expression = note.noteExpressions.FirstOrDefault(exp => exp.descriptor == descriptor);
if (expression != null) {
expression.value = value;
} else {
note.noteExpressions.Add(new UExpression(descriptor) {
descriptor = descriptor,
value = value,
});
int indexes = (phonemeExpressions.Max(exp => exp.index) ?? 0) + 1;

for (int i = 0; i < indexes; i++) {
float value;
if (values.Length > i) {
value = values[i];
} else {
value = values.Last();
}

if (descriptor.defaultValue == value) {
phonemeExpressions.RemoveAll(exp => exp.descriptor?.abbr == descriptor.abbr && exp.index == i);
continue;
}
var expression = phonemeExpressions.FirstOrDefault(exp => exp.descriptor?.abbr == descriptor.abbr && exp.index == i);
if (expression != null) {
expression.descriptor = descriptor;
expression.value = value;
} else {
phonemeExpressions.Add(new UExpression(descriptor) {
descriptor = descriptor,
index = i,
value = value,
});
}
}
}
*/

public UNote Clone() {
return new UNote() {
Expand Down
3 changes: 3 additions & 0 deletions OpenUtau/OpenUtau.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="Views\PasteParamDialog.axaml.cs">
<DependentUpon>PasteParamDialog.axaml</DependentUpon>
</Compile>
<Compile Update="Views\TrackSettingsDialog.axaml.cs">
<DependentUpon>TrackSettingsDialog.axaml</DependentUpon>
</Compile>
Expand Down
1 change: 1 addition & 0 deletions OpenUtau/Strings/Strings.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="context.note.copy">Copy note</system:String>
<system:String x:Key="context.note.delete">Delete note</system:String>
<system:String x:Key="context.note.pasteparameters">Select and paste parameters</system:String>
<system:String x:Key="context.part.delete">Delete part</system:String>
<system:String x:Key="context.part.rename">Rename part</system:String>
<system:String x:Key="context.part.replaceaudio">Reselect audio file</system:String>
Expand Down
1 change: 1 addition & 0 deletions OpenUtau/Strings/Strings.ja-JP.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="context.note.copy">音符をコピー</system:String>
<system:String x:Key="context.note.delete">音符を削除</system:String>
<system:String x:Key="context.note.pasteparameters">パラメータを選択して貼り付け</system:String>
<system:String x:Key="context.part.delete">パートを削除</system:String>
<system:String x:Key="context.part.rename">パートの名前を変更</system:String>
<system:String x:Key="context.part.replaceaudio">オーディオファイルを変更</system:String>
Expand Down
58 changes: 58 additions & 0 deletions OpenUtau/ViewModels/NotesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Avalonia.Media.Imaging;
using DynamicData;
using DynamicData.Binding;
using OpenUtau.App.Views;
using OpenUtau.Core;
using OpenUtau.Core.Ustx;
using OpenUtau.Core.Util;
Expand Down Expand Up @@ -760,6 +761,63 @@ public void PasteNotes() {
}
}

public async void PasteSelectedParams(PianoRollWindow window) {
if (Part != null && DocManager.Inst.NotesClipboard != null && DocManager.Inst.NotesClipboard.Count > 0) {
var selectedNotes = Selection.ToList();
if(selectedNotes.Count == 0) {
return;
}

var dialog = new PasteParamDialog();
var vm = new PasteParamViewModel();
dialog.DataContext = vm;
await dialog.ShowDialog(window);

if (dialog.Apply) {
DocManager.Inst.StartUndoGroup();

int c = 0;
var track = Project.tracks[Part.trackNo];
foreach (var note in selectedNotes) {
var copyNote = DocManager.Inst.NotesClipboard[c];

for (int i = 0; i < vm.Params.Count; i++) {
switch (i) {
case 0:
if (vm.Params[i].IsSelected) {
DocManager.Inst.ExecuteCmd(new SetPitchPointsCommand(Part, note, copyNote.pitch));
}
break;
case 1:
if (vm.Params[i].IsSelected) {
DocManager.Inst.ExecuteCmd(new VibratoLengthCommand(Part, note, copyNote.vibrato.length));
DocManager.Inst.ExecuteCmd(new VibratoDepthCommand(Part, note, copyNote.vibrato.depth));
DocManager.Inst.ExecuteCmd(new VibratoPeriodCommand(Part, note, copyNote.vibrato.period));
DocManager.Inst.ExecuteCmd(new VibratoFadeInCommand(Part, note, copyNote.vibrato.@in));
DocManager.Inst.ExecuteCmd(new VibratoFadeOutCommand(Part, note, copyNote.vibrato.@out));
DocManager.Inst.ExecuteCmd(new VibratoShiftCommand(Part, note, copyNote.vibrato.shift));
// DocManager.Inst.ExecuteCmd(new VibratoDriftCommand(Part, note, copyNote.vibrato.drift));
}
break;
default:
if (vm.Params[i].IsSelected) {
float[] values = copyNote.GetExpression(Project, track, vm.Params[i].Abbr).Select(t => t.Item1).ToArray();
DocManager.Inst.ExecuteCmd(new SetNoteExpressionCommand(Project, track, Part, note, vm.Params[i].Abbr, values));
}
break;
}
}

c++;
if (c >= DocManager.Inst.NotesClipboard.Count) {
c = 0;
}
}
DocManager.Inst.EndUndoGroup();
}
}
}

public void ToggleVibrato(UNote note) {
if (Part == null) {
return;
Expand Down
33 changes: 33 additions & 0 deletions OpenUtau/ViewModels/PasteParamViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections.ObjectModel;
using OpenUtau.Core;
using ReactiveUI.Fody.Helpers;

namespace OpenUtau.App.ViewModels {
public class PasteParamViewModel {

public PasteParamViewModel() {
Params.Add(new PasteParameter("pitch points", ""));
Params.Add(new PasteParameter("vibrato", ""));
foreach(var exp in DocManager.Inst.Project.expressions) {
if(exp.Value.type != Core.Ustx.UExpressionType.Curve) {
Params.Add(new PasteParameter(exp.Value.name, exp.Key));
}
}
Params[0].IsSelected = true;
}

public ObservableCollection<PasteParameter> Params { get; } = new ObservableCollection<PasteParameter>();
}

public class PasteParameter {
public PasteParameter(string name, string abbr) {
Name = name;
Abbr = abbr;
}
public string Name { get; set; }
public string Abbr { get; set; }
[Reactive] public bool IsSelected { get; set; } = false;

public override string ToString() { return Name; }
}
}
23 changes: 23 additions & 0 deletions OpenUtau/Views/PasteParamDialog.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" MinWidth="200" MinHeight="200" Width="300" Height="350"
x:Class="OpenUtau.App.Views.PasteParamDialog"
Icon="/Assets/open-utau.ico"
Title="{DynamicResource context.note.pasteparameters}"
WindowStartupLocation="CenterScreen"
ExtendClientAreaToDecorationsHint="False">
<Grid RowDefinitions="*, 40" >
<ListBox SelectionMode="Multiple,Toggle" ItemsSource="{Binding Params}"
Grid.Row="0" Margin="10" ScrollViewer.VerticalScrollBarVisibility="Auto" Background="Transparent" >
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.Styles>
</ListBox>

<Button Content="OK" Click="OkButtonClick" Grid.Row="1" Width="100" HorizontalAlignment="Center"/>
</Grid>
</Window>
34 changes: 34 additions & 0 deletions OpenUtau/Views/PasteParamDialog.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;

namespace OpenUtau.App.Views {
public partial class PasteParamDialog : Window {
public bool Apply { get; private set; } = false;

public PasteParamDialog() {
InitializeComponent();
}

private void OkButtonClick(object? sender, RoutedEventArgs e) {
Finish();
}

private void Finish() {
Apply = true;
Close();
}

protected override void OnKeyDown(KeyEventArgs e) {
if (e.Key == Key.Escape) {
e.Handled = true;
Close();
} else if (e.Key == Key.Enter) {
e.Handled = true;
Finish();
} else {
base.OnKeyDown(e);
}
}
}
}
8 changes: 8 additions & 0 deletions OpenUtau/Views/PianoRollWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,10 @@ private void NotesCanvasRightPointerPressed(Control control, PointerPoint point,
Command = ViewModel.NoteDeleteCommand,
CommandParameter = hitInfo,
});
ViewModel.NotesContextMenuItems.Add(new MenuItemViewModel() {
Header = ThemeManager.GetString("context.note.pasteparameters"),
Command = ReactiveCommand.Create(() => ViewModel.NotesViewModel.PasteSelectedParams(this))
});
ViewModel.NotesContextMenuItems.Add(new MenuItemViewModel() {
Header = ThemeManager.GetString("pianoroll.menu.notes"),
Items = ViewModel.NoteBatchEdits.ToArray(),
Expand Down Expand Up @@ -1112,6 +1116,10 @@ bool OnKeyExtendedHandler(KeyEventArgs args) {
notesVm.PasteNotes();
return true;
}
if (isAlt) {
notesVm.PasteSelectedParams(this);
return true;
}
break;
// INSERT + DELETE
case Key.Insert:
Expand Down

0 comments on commit 3ed4bd4

Please sign in to comment.