From 631007059751cebf45b75027d97f754628d931fa Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Mon, 9 Feb 2026 19:26:53 -0500
Subject: [PATCH 01/10] add SimplexNoise
---
OpenUtau.Core/ThirdParty/SimplexNoise.cs | 455 +++++++++++++++++++++++
1 file changed, 455 insertions(+)
create mode 100644 OpenUtau.Core/ThirdParty/SimplexNoise.cs
diff --git a/OpenUtau.Core/ThirdParty/SimplexNoise.cs b/OpenUtau.Core/ThirdParty/SimplexNoise.cs
new file mode 100644
index 000000000..8258fabed
--- /dev/null
+++ b/OpenUtau.Core/ThirdParty/SimplexNoise.cs
@@ -0,0 +1,455 @@
+/*
+BSD 3-Clause License
+
+Copyright (c) 2019, Benjamin Ward
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Simplex Noise for C#
+// Copyright © Benjamin Ward 2019
+// See LICENSE
+// Simplex Noise implementation offering 1D, 2D, and 3D forms w/ values in the range of 0 to 255.
+// Based on work by Heikki Törmälä (2012) and Stefan Gustavson (2006).
+
+using System;
+
+namespace SimplexNoise
+{
+ ///
+ /// Implementation of the Perlin simplex noise, an improved Perlin noise algorithm.
+ /// Based loosely on SimplexNoise1234 by Stefan Gustavson: http://staffwww.itn.liu.se/~stegu/aqsis/aqsis-newnoise/
+ ///
+ public static class Noise
+ {
+ ///
+ /// Creates 1D Simplex noise
+ ///
+ /// The number of points to generate
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// An array containing 1D Simplex noise
+ public static float[] Calc1D(int width, float scale)
+ {
+ var values = new float[width];
+ for (var i = 0; i < width; i++)
+ values[i] = Generate(i * scale) * 128 + 128;
+ return values;
+ }
+
+ ///
+ /// Creates 2D Simplex noise
+ ///
+ /// The number of points to generate in the 1st dimension
+ /// The number of points to generate in the 2nd dimension
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// An array containing 2D Simplex noise
+ public static float[,] Calc2D(int width, int height, float scale)
+ {
+ var values = new float[width, height];
+ for (var i = 0; i < width; i++)
+ for (var j = 0; j < height; j++)
+ values[i, j] = Generate(i * scale, j * scale) * 128 + 128;
+ return values;
+ }
+
+ ///
+ /// Creates 3D Simplex noise
+ ///
+ /// The number of points to generate in the 1st dimension
+ /// The number of points to generate in the 2nd dimension
+ /// The number of points to generate in the 3nd dimension
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// An array containing 3D Simplex noise
+ public static float[, ,] Calc3D(int width, int height, int length, float scale)
+ {
+ var values = new float[width, height, length];
+ for (var i = 0; i < width; i++)
+ for (var j = 0; j < height; j++)
+ for (var k = 0; k < length; k++)
+ values[i, j, k] = Generate(i * scale, j * scale, k * scale) * 128 + 128;
+ return values;
+ }
+
+ ///
+ /// Gets the value of an index of 1D simplex noise
+ ///
+ /// Index
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// The value of an index of 1D simplex noise
+ public static float CalcPixel1D(int x, float scale)
+ {
+ return Generate(x * scale) * 128 + 128;
+ }
+
+ ///
+ /// Gets the value of an index of 2D simplex noise
+ ///
+ /// 1st dimension index
+ /// 2st dimension index
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// The value of an index of 2D simplex noise
+ public static float CalcPixel2D(int x, int y, float scale)
+ {
+ return Generate(x * scale, y * scale) * 128 + 128;
+ }
+
+
+ ///
+ /// Gets the value of an index of 3D simplex noise
+ ///
+ /// 1st dimension index
+ /// 2nd dimension index
+ /// 3rd dimension index
+ /// The scale of the noise. The greater the scale, the denser the noise gets
+ /// The value of an index of 3D simplex noise
+ public static float CalcPixel3D(int x, int y, int z, float scale)
+ {
+ return Generate(x * scale, y * scale, z * scale) * 128 + 128;
+ }
+
+ static Noise()
+ {
+ _perm = new byte[PermOriginal.Length];
+ PermOriginal.CopyTo(_perm, 0);
+ }
+
+ ///
+ /// Arbitrary integer seed used to generate lookup table used internally
+ ///
+ public static int Seed
+ {
+ get => _seed;
+ set
+ {
+ if (value == 0)
+ {
+ _perm = new byte[PermOriginal.Length];
+ PermOriginal.CopyTo(_perm, 0);
+ }
+ else
+ {
+ // Begin discontinuity fix by @ntark //
+
+ // Fixes issue #7 and #8
+ // https://github.com/WardBenjamin/SimplexNoise/pull/13
+ // permutation matrix is duplicated to handle rollovers
+ _perm = new byte[512];
+
+ var perm = new byte[256];
+ new Random(value).NextBytes(perm);
+
+ Array.Copy(perm, 0, _perm, 0, 256);
+ Array.Copy(perm, 0, _perm, 256, 256);
+
+ // End discontinuity fix //
+ }
+
+ _seed = value;
+ }
+ }
+
+ private static int _seed;
+
+ ///
+ /// 1D simplex noise
+ ///
+ ///
+ ///
+ public static float Generate(float x) // made public
+ {
+ var i0 = FastFloor(x);
+ var i1 = i0 + 1;
+ var x0 = x - i0;
+ var x1 = x0 - 1.0f;
+
+ var t0 = 1.0f - x0 * x0;
+ t0 *= t0;
+ var n0 = t0 * t0 * Grad(_perm[i0 & 0xff], x0);
+
+ var t1 = 1.0f - x1 * x1;
+ t1 *= t1;
+ var n1 = t1 * t1 * Grad(_perm[i1 & 0xff], x1);
+ // The maximum value of this noise is 8*(3/4)^4 = 2.53125
+ // A factor of 0.395 scales to fit exactly within [-1,1]
+ return 0.395f * (n0 + n1);
+ }
+
+ ///
+ /// 2D simplex noise
+ ///
+ ///
+ ///
+ ///
+ public static float Generate(float x, float y) // made public
+ {
+ const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0)
+ const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0
+
+ float n0, n1, n2; // Noise contributions from the three corners
+
+ // Skew the input space to determine which simplex cell we're in
+ var s = (x + y) * F2; // Hairy factor for 2D
+ var xs = x + s;
+ var ys = y + s;
+ var i = FastFloor(xs);
+ var j = FastFloor(ys);
+
+ var t = (i + j) * G2;
+ var X0 = i - t; // Unskew the cell origin back to (x,y) space
+ var Y0 = j - t;
+ var x0 = x - X0; // The x,y distances from the cell origin
+ var y0 = y - Y0;
+
+ // For the 2D case, the simplex shape is an equilateral triangle.
+ // Determine which simplex we are in.
+ int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
+ if (x0 > y0) { i1 = 1; j1 = 0; } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
+ else { i1 = 0; j1 = 1; } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
+
+ // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
+ // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
+ // c = (3-sqrt(3))/6
+
+ var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
+ var y1 = y0 - j1 + G2;
+ var x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
+ var y2 = y0 - 1.0f + 2.0f * G2;
+
+ // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
+ var ii = Mod(i, 256);
+ var jj = Mod(j, 256);
+
+ // Calculate the contribution from the three corners
+ var t0 = 0.5f - x0 * x0 - y0 * y0;
+ if (t0 < 0.0f) n0 = 0.0f;
+ else
+ {
+ t0 *= t0;
+ n0 = t0 * t0 * Grad(_perm[ii + _perm[jj]], x0, y0);
+ }
+
+ var t1 = 0.5f - x1 * x1 - y1 * y1;
+ if (t1 < 0.0f) n1 = 0.0f;
+ else
+ {
+ t1 *= t1;
+ n1 = t1 * t1 * Grad(_perm[ii + i1 + _perm[jj + j1]], x1, y1);
+ }
+
+ var t2 = 0.5f - x2 * x2 - y2 * y2;
+ if (t2 < 0.0f) n2 = 0.0f;
+ else
+ {
+ t2 *= t2;
+ n2 = t2 * t2 * Grad(_perm[ii + 1 + _perm[jj + 1]], x2, y2);
+ }
+
+ // Add contributions from each corner to get the final noise value.
+ // The result is scaled to return values in the interval [-1,1].
+ return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
+ }
+
+
+ public static float Generate(float x, float y, float z) // made public
+ {
+ // Simple skewing factors for the 3D case
+ const float F3 = 0.333333333f;
+ const float G3 = 0.166666667f;
+
+ float n0, n1, n2, n3; // Noise contributions from the four corners
+
+ // Skew the input space to determine which simplex cell we're in
+ var s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
+ var xs = x + s;
+ var ys = y + s;
+ var zs = z + s;
+ var i = FastFloor(xs);
+ var j = FastFloor(ys);
+ var k = FastFloor(zs);
+
+ var t = (i + j + k) * G3;
+ var X0 = i - t; // Unskew the cell origin back to (x,y,z) space
+ var Y0 = j - t;
+ var Z0 = k - t;
+ var x0 = x - X0; // The x,y,z distances from the cell origin
+ var y0 = y - Y0;
+ var z0 = z - Z0;
+
+ // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+ // Determine which simplex we are in.
+ int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
+ int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
+
+ /* This code would benefit from a backport from the GLSL version! */
+ if (x0 >= y0)
+ {
+ if (y0 >= z0)
+ { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order
+ else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order
+ else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order
+ }
+ else
+ { // x0 0) ? ((int)x) : (((int)x) - 1);
+ }
+
+ private static int Mod(int x, int m)
+ {
+ var a = x % m;
+ return a < 0 ? a + m : a;
+ }
+
+ private static float Grad(int hash, float x)
+ {
+ var h = hash & 15;
+ var grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
+ if ((h & 8) != 0) grad = -grad; // Set a random sign for the gradient
+ return (grad * x); // Multiply the gradient with the distance
+ }
+
+ private static float Grad(int hash, float x, float y)
+ {
+ var h = hash & 7; // Convert low 3 bits of hash code
+ var u = h < 4 ? x : y; // into 8 simple gradient directions,
+ var v = h < 4 ? y : x; // and compute the dot product with (x,y).
+ return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v);
+ }
+
+ private static float Grad(int hash, float x, float y, float z)
+ {
+ var h = hash & 15; // Convert low 4 bits of hash code into 12 simple
+ var u = h < 8 ? x : y; // gradient directions, and compute dot product.
+ var v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15
+ return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v);
+ }
+
+ private static float Grad(int hash, float x, float y, float z, float t)
+ {
+ var h = hash & 31; // Convert low 5 bits of hash code into 32 simple
+ var u = h < 24 ? x : y; // gradient directions, and compute dot product.
+ var v = h < 16 ? y : z;
+ var w = h < 8 ? z : t;
+ return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v) + ((h & 4) != 0 ? -w : w);
+ }
+ }
+}
From dee9b16e7bfcc55cd3bb800c01665dff22d47aa6 Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Mon, 9 Feb 2026 19:29:04 -0500
Subject: [PATCH 02/10] add new vibrato variance fields & behavior
---
OpenUtau.Core/Commands/NoteCommands.cs | 107 +++++++++++++++++++++++++
OpenUtau.Core/Ustx/UNote.cs | 46 ++++++++++-
OpenUtau.Core/Util/NotePresets.cs | 22 +++--
3 files changed, 166 insertions(+), 9 deletions(-)
diff --git a/OpenUtau.Core/Commands/NoteCommands.cs b/OpenUtau.Core/Commands/NoteCommands.cs
index 85bde011f..259607aab 100644
--- a/OpenUtau.Core/Commands/NoteCommands.cs
+++ b/OpenUtau.Core/Commands/NoteCommands.cs
@@ -454,6 +454,113 @@ public override void Unexecute() {
}
}
+ public class VibratoVarianceDepthCommand : VibratoCommand {
+ readonly UNote note;
+ readonly float newVariance;
+ readonly float oldVariance;
+
+ public VibratoVarianceDepthCommand(UVoicePart part, UNote note, float variance) : base(part, note) {
+ this.note = note;
+ newVariance = variance;
+ oldVariance = note.vibrato.variance;
+ }
+
+ public override string ToString() {
+ return "Change vibrato variance depth";
+ }
+
+ public override void Execute() {
+ lock (Part) {
+ note.vibrato.variance = newVariance;
+ }
+ }
+ public override void Unexecute() {
+ lock (Part) {
+ note.vibrato.variance = oldVariance;
+ }
+ }
+ }
+
+ public class VibratoPitchVarianceCommand : VibratoCommand {
+ readonly UNote note;
+ readonly float newPitchVariance;
+ readonly float oldPitchVariance;
+
+ public VibratoPitchVarianceCommand(UVoicePart part, UNote note, float pitchVariance) : base(part, note) {
+ this.note = note;
+ newPitchVariance = pitchVariance;
+ oldPitchVariance = note.vibrato.pitchVariance;
+ }
+
+ public override string ToString() {
+ return "Change vibrato pitch variance depth";
+ }
+
+ public override void Execute() {
+ lock (Part) {
+ note.vibrato.pitchVariance = newPitchVariance;
+ }
+ }
+ public override void Unexecute() {
+ lock (Part) {
+ note.vibrato.pitchVariance = oldPitchVariance;
+ }
+ }
+ }
+
+ public class VibratoVarianceFrequencyCommand : VibratoCommand {
+ readonly UNote note;
+ readonly float newVarianceFreq;
+ readonly float oldVarianceFreq;
+
+ public VibratoVarianceFrequencyCommand(UVoicePart part, UNote note, float frequency) : base(part, note) {
+ this.note = note;
+ newVarianceFreq = frequency;
+ oldVarianceFreq = note.vibrato.varianceFreq;
+ }
+
+ public override string ToString() {
+ return "Change vibrato variance frequency";
+ }
+
+ public override void Execute() {
+ lock (Part) {
+ note.vibrato.varianceFreq = newVarianceFreq;
+ }
+ }
+ public override void Unexecute() {
+ lock (Part) {
+ note.vibrato.varianceFreq = oldVarianceFreq;
+ }
+ }
+ }
+
+ public class VibratoVarianceSeedCommand : VibratoCommand {
+ readonly UNote note;
+ readonly int newVarianceSeed;
+ readonly int oldVarianceSeed;
+
+ public VibratoVarianceSeedCommand(UVoicePart part, UNote note, int seed) : base(part, note) {
+ this.note = note;
+ newVarianceSeed = seed;
+ oldVarianceSeed = note.vibrato.varianceSeed;
+ }
+
+ public override string ToString() {
+ return "Change vibrato variance seed";
+ }
+
+ public override void Execute() {
+ lock (Part) {
+ note.vibrato.varianceSeed = newVarianceSeed;
+ }
+ }
+ public override void Unexecute() {
+ lock (Part) {
+ note.vibrato.varianceSeed = oldVarianceSeed;
+ }
+ }
+ }
public class PhonemeOffsetCommand : NoteCommand {
readonly UNote note;
diff --git a/OpenUtau.Core/Ustx/UNote.cs b/OpenUtau.Core/Ustx/UNote.cs
index e4c8bd144..c73a7c983 100644
--- a/OpenUtau.Core/Ustx/UNote.cs
+++ b/OpenUtau.Core/Ustx/UNote.cs
@@ -6,6 +6,7 @@
using OpenUtau.Api;
using OpenUtau.Core.Util;
using YamlDotNet.Serialization;
+using SimplexNoise;
namespace OpenUtau.Core.Ustx {
public class UNote : IComparable {
@@ -281,6 +282,14 @@ public class UVibrato {
float _drift = NotePresets.Default.DefaultVibrato.VibratoDrift;
// Percentage of volume reduction in linkage with vibrato. When this is 100%, volume will be 1.2 times to 0.2 times regardless of depth.
float _volLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
+ // Amount of variance in the shape of the vibrato curve.
+ float _variance = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ // Amount of variance in the intensity of the vibrato curve.
+ float _pitchVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ // Frequency of variance in the shape of the vibrato curve.
+ float _varianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ // Random seed used for vibrato variance
+ int _varianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
public float length { get => _length; set => _length = Math.Max(0, Math.Min(100, value)); }
public float period { get => _period; set => _period = Math.Max(5, Math.Min(500, value)); }
@@ -305,6 +314,11 @@ public float @out {
public float drift { get => _drift; set => _drift = Math.Max(-100, Math.Min(100, value)); }
public float volLink { get => _volLink; set => _volLink = Math.Max(-100, Math.Min(100, value)); }
+ public float variance { get => _variance; set => _variance = Math.Max(0, Math.Min(2, value)); }
+ public float pitchVariance { get => _pitchVariance; set => _pitchVariance = Math.Max(0, Math.Min(2, value)); }
+ public float varianceFreq { get => _varianceFreq; set => _varianceFreq = Math.Max(0.1F, Math.Min(8, value)); }
+ public int varianceSeed { get => _varianceSeed; set => _varianceSeed = value; }
+
[YamlIgnore] public float NormalizedStart => 1f - length / 100f;
public UVibrato Clone() {
@@ -316,7 +330,11 @@ public UVibrato Clone() {
@out = @out,
shift = shift,
drift = drift,
- volLink = volLink
+ volLink = volLink,
+ variance = variance,
+ pitchVariance = pitchVariance,
+ varianceFreq = varianceFreq,
+ varianceSeed = varianceSeed
};
return result;
}
@@ -338,7 +356,19 @@ public Vector2 Evaluate(float nPos, float nPeriod, UNote note) {
float nOut = length / 100f * @out / 100f;
float nOutPos = 1f - nOut;
float t = (nPos - nStart) / nPeriod + shift / 100f;
- float y = (float)Math.Sin(2 * Math.PI * t) * depth + (depth / 100 * drift);
+ float y;
+ if(variance > 0 || pitchVariance > 0) {
+ Noise.Seed = varianceSeed; // setting seed might need optimization
+ // * 0.33F so it has a reasonable base value, it's too much at unity
+ float variancePhaseShift = Noise.Generate(t * varianceFreq) * 0.33F;
+ Noise.Seed = varianceSeed + 1;
+ float pitchNoise = Noise.Generate(t * varianceFreq) * 100 * pitchVariance;
+ t += variancePhaseShift * variance;
+ float normalizedDepth = 200 * ((depth - 5) / (200 - 5));
+ y = (float)Math.Sin(2 * Math.PI * t) * depth + (depth / 100 * drift) + (normalizedDepth / 100 * pitchNoise);
+ } else {
+ y = (float)Math.Sin(2 * Math.PI * t) * depth + (depth / 100 * drift);
+ }
if (nPos < nStart) {
y = 0;
} else if (nPos < nInPos) {
@@ -367,7 +397,17 @@ public float EvaluateVolume(float nPos, float nPeriod) {
volLink *= -1;
}
float t = (nPos - nStart) / nPeriod + shift / 100f;
- float reduction = (-(float)Math.Sin(2 * Math.PI * t) / 2 + 0.3f) * volLink / 100;
+ float reduction;
+ if(variance > 0) {
+ Noise.Seed = varianceSeed; // setting seed might need optimization
+ // * 0.33F so it has a reasonable base value, it's too much at unity
+ // TODO actually use pitch variance to influence volume link too??
+ float variancePhaseShift = Noise.Generate(t * varianceFreq) * 0.33F;
+ t += variancePhaseShift * variance;
+ reduction = (-(float)Math.Sin(2 * Math.PI * t) / 2 + 0.3f) * volLink / 100;
+ } else {
+ reduction = (-(float)Math.Sin(2 * Math.PI * t) / 2 + 0.3f) * volLink / 100;
+ }
if (nPos < nStart) {
reduction = 0;
} else if (nPos < nInPos) {
diff --git a/OpenUtau.Core/Util/NotePresets.cs b/OpenUtau.Core/Util/NotePresets.cs
index 7a46e715b..b8cefb802 100644
--- a/OpenUtau.Core/Util/NotePresets.cs
+++ b/OpenUtau.Core/Util/NotePresets.cs
@@ -46,10 +46,10 @@ public static void Reset() {
new PortamentoPreset("Snap", 2, -1),
});
Default.VibratoPresets.AddRange(new List {
- new VibratoPreset("Standard", 75, 175, 25, 10, 10, 0, 0, 0),
- new VibratoPreset("UTAU Default", 65, 180, 35, 20, 20, 0, 0, 0),
- new VibratoPreset("UTAU Strong", 65, 210, 55, 25, 25, 0, 0, 0),
- new VibratoPreset("UTAU Weak", 65, 165, 20, 25, 25, 0, 0, 0)
+ new VibratoPreset("Standard", 75, 175, 25, 10, 10, 0, 0, 0, 0, 0, 1, 0),
+ new VibratoPreset("UTAU Default", 65, 180, 35, 20, 20, 0, 0, 0, 0, 0, 1, 0),
+ new VibratoPreset("UTAU Strong", 65, 210, 55, 25, 25, 0, 0, 0, 0, 0, 1, 0),
+ new VibratoPreset("UTAU Weak", 65, 165, 20, 25, 25, 0, 0, 0, 0, 0, 1, 0)
});
Save();
@@ -61,7 +61,7 @@ public class SerializableNotePresets {
public string SplittedLyric = "+";
public PortamentoPreset DefaultPortamento = new PortamentoPreset("Standard", 80, -40);
public List PortamentoPresets = new List { };
- public VibratoPreset DefaultVibrato = new VibratoPreset("Standard", 75, 175, 25, 10, 10, 0, 0, 0);
+ public VibratoPreset DefaultVibrato = new VibratoPreset();
public List VibratoPresets = new List { };
public bool AutoVibratoToggle = false;
public int AutoVibratoNoteDuration = 481;
@@ -91,8 +91,12 @@ public class VibratoPreset {
public float VibratoShift = 0;
public float VibratoDrift = 0;
public float VibratoVolLink = 0;
+ public float VibratoVariance = 0;
+ public float VibratoPitchVariance = 0;
+ public float VibratoVarianceFreq = 1;
+ public int VibratoVarianceSeed = 0;
- public VibratoPreset(string name, float length, float period, float depth, float fadein, float fadeout, float shift, float drift, float volLink) {
+ public VibratoPreset(string name, float length, float period, float depth, float fadein, float fadeout, float shift, float drift, float volLink, float variance, float pitchVariance, float varianceFrequency, int varianceSeed) {
Name = name;
VibratoLength = length;
VibratoPeriod = period;
@@ -102,8 +106,14 @@ public VibratoPreset(string name, float length, float period, float depth, float
VibratoShift = shift;
VibratoDrift = drift;
VibratoVolLink = volLink;
+ VibratoVariance = variance;
+ VibratoPitchVariance = pitchVariance;
+ VibratoVarianceFreq = varianceFrequency;
+ VibratoVarianceSeed = varianceSeed;
}
+ public VibratoPreset() {}
+
public override string ToString() => Name;
}
From 1275719dd9f5d34c94383f316db28c0af1189d8b Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Mon, 9 Feb 2026 19:29:19 -0500
Subject: [PATCH 03/10] bump ustx format version
---
OpenUtau.Core/Format/USTx.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/OpenUtau.Core/Format/USTx.cs b/OpenUtau.Core/Format/USTx.cs
index 4922d0918..c657c4dd7 100644
--- a/OpenUtau.Core/Format/USTx.cs
+++ b/OpenUtau.Core/Format/USTx.cs
@@ -10,7 +10,7 @@
namespace OpenUtau.Core.Format {
public class Ustx {
- public static readonly Version kUstxVersion = new Version(0, 9);
+ public static readonly Version kUstxVersion = new Version(0, 9, 1);
public const string DYN = "dyn";
public const string PITD = "pitd";
From 414d3f219011a6e700ef3215af891682446d628e Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Mon, 9 Feb 2026 19:30:56 -0500
Subject: [PATCH 04/10] vibrato variance UI controls
---
OpenUtau/Controls/NotePropertiesControl.axaml | 29 +++++++
.../Controls/NotePropertiesControl.axaml.cs | 6 ++
OpenUtau/Strings/Strings.axaml | 8 ++
OpenUtau/ViewModels/NoteDefaultsViewModel.cs | 41 +++++++++-
.../ViewModels/NotePropertiesViewModel.cs | 82 ++++++++++++++++++-
OpenUtau/Views/NoteDefaultsDialog.axaml | 23 ++++++
6 files changed, 187 insertions(+), 2 deletions(-)
diff --git a/OpenUtau/Controls/NotePropertiesControl.axaml b/OpenUtau/Controls/NotePropertiesControl.axaml
index 2d1921a3c..92d979e4b 100644
--- a/OpenUtau/Controls/NotePropertiesControl.axaml
+++ b/OpenUtau/Controls/NotePropertiesControl.axaml
@@ -146,6 +146,35 @@
TickPlacement="BottomRight" TickFrequency="0.1" IsSnapToTickEnabled="true"
Tag="VibratoVolLink"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenUtau/Controls/NotePropertiesControl.axaml.cs b/OpenUtau/Controls/NotePropertiesControl.axaml.cs
index 80cb94531..d8333155b 100644
--- a/OpenUtau/Controls/NotePropertiesControl.axaml.cs
+++ b/OpenUtau/Controls/NotePropertiesControl.axaml.cs
@@ -137,6 +137,12 @@ void OnSaveVibratoPreset(object sender, RoutedEventArgs e) {
}
}
+ void OnNewVarianceSeed(object sender, RoutedEventArgs e) {
+ int newSeed = Random.Shared.Next();
+ ViewModel.SetVibratoVarianceSeed(newSeed);
+ ViewModel.VarianceSeed = newSeed;
+ }
+
void OnRemoveVibratoPreset(object sender, RoutedEventArgs e) {
ViewModel.RemoveAppliedVibratoPreset();
}
diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml
index 477d6aaad..d22e81b88 100644
--- a/OpenUtau/Strings/Strings.axaml
+++ b/OpenUtau/Strings/Strings.axaml
@@ -334,6 +334,13 @@ Warning: this option removes custom presets.
Period
Shift
Volume Link
+ Variance
+ Depth Variance
+ Variance Seed
+ Variance Frequency
+ New Seed
+ Amount of random variation in the shape of the vibrato curve. At 0, this setting has no effect on the vibrato.
+ Amount of random variation in the intensity of vibrato. This setting is independent of Variance, but inherits the Variance Seed and Variance Frequency settings. At 0, this setting has no effect on the vibrato.
Note Properties
Apply
@@ -437,6 +444,7 @@ Warning: this option removes custom presets.
Randomize phoneme offset
Randomize note timing
Randomize tuning
+ Randomize pitch deviation
Refresh real curves
Remove tail "-"
Remove tail "R"
diff --git a/OpenUtau/ViewModels/NoteDefaultsViewModel.cs b/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
index f8f15d5d9..79de42273 100644
--- a/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
+++ b/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
@@ -21,6 +21,10 @@ class NoteDefaultsViewModel : ViewModelBase {
[Reactive] public float CurrentVibratoShift { get; set; }
[Reactive] public float CurrentVibratoDrift { get; set; }
[Reactive] public float CurrentVibratoVolLink { get; set; }
+ [Reactive] public float CurrentVibratoVariance { get; set; }
+ [Reactive] public float CurrentVibratoPitchVariance { get; set; }
+ [Reactive] public float CurrentVibratoVarianceFreq { get; set; }
+ [Reactive] public int CurrentVibratoVarianceSeed { get; set; }
[Reactive] public float AutoVibratoNoteLength { get; set; }
[Reactive] public bool AutoVibratoToggle { get; set; }
public List? PortamentoPresets { get; }
@@ -52,6 +56,9 @@ public NoteDefaultsViewModel() {
CurrentVibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
CurrentVibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
CurrentVibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
+ CurrentVibratoVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ CurrentVibratoVarianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ CurrentVibratoVarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
PortamentoPresets = NotePresets.Default.PortamentoPresets;
@@ -127,6 +134,26 @@ public NoteDefaultsViewModel() {
NotePresets.Default.DefaultVibrato.VibratoVolLink = Math.Max(-100, Math.Min(100, vibratoVolLink));
NotePresets.Save();
});
+ this.WhenAnyValue(vm => vm.CurrentVibratoVariance)
+ .Subscribe(vibratoVariance => {
+ NotePresets.Default.DefaultVibrato.VibratoVariance = Math.Max(0, Math.Min(4, vibratoVariance));
+ NotePresets.Save();
+ });
+ this.WhenAnyValue(vm => vm.CurrentVibratoPitchVariance)
+ .Subscribe(vibratoPitchVariance => {
+ NotePresets.Default.DefaultVibrato.VibratoPitchVariance = Math.Max(0, Math.Min(4, vibratoPitchVariance));
+ NotePresets.Save();
+ });
+ this.WhenAnyValue(vm => vm.CurrentVibratoVarianceFreq)
+ .Subscribe(vibratoVarianceFreq => {
+ NotePresets.Default.DefaultVibrato.VibratoVarianceFreq = Math.Max(0.1F, Math.Min(8, vibratoVarianceFreq));
+ NotePresets.Save();
+ });
+ this.WhenAnyValue(vm => vm.CurrentVibratoVarianceSeed)
+ .Subscribe(vibratoVarianceSeed => {
+ NotePresets.Default.DefaultVibrato.VibratoVarianceSeed = vibratoVarianceSeed;
+ NotePresets.Save();
+ });
this.WhenAnyValue(vm => vm.AutoVibratoToggle)
.Subscribe(autoVibratoToggle => {
NotePresets.Default.AutoVibratoToggle = autoVibratoToggle;
@@ -160,6 +187,10 @@ public NoteDefaultsViewModel() {
CurrentVibratoShift = Math.Max(0, Math.Min(100, vibratoPreset.VibratoShift));
CurrentVibratoDrift = Math.Max(-100, Math.Min(100, vibratoPreset.VibratoDrift));
CurrentVibratoVolLink = Math.Max(-100, Math.Min(100, vibratoPreset.VibratoVolLink));
+ CurrentVibratoVariance = Math.Max(0, Math.Min(4, vibratoPreset.VibratoVariance));
+ CurrentVibratoPitchVariance = Math.Max(0, Math.Min(4, vibratoPreset.VibratoPitchVariance));
+ CurrentVibratoVarianceFreq = Math.Max(0.1F, Math.Min(8, vibratoPreset.VibratoVarianceFreq));
+ CurrentVibratoVarianceSeed = vibratoPreset.VibratoVarianceSeed;
NotePresets.Default.DefaultVibrato.VibratoLength = CurrentVibratoLength;
NotePresets.Default.DefaultVibrato.VibratoPeriod = CurrentVibratoPeriod;
NotePresets.Default.DefaultVibrato.VibratoDepth = CurrentVibratoDepth;
@@ -168,6 +199,10 @@ public NoteDefaultsViewModel() {
NotePresets.Default.DefaultVibrato.VibratoShift = CurrentVibratoShift;
NotePresets.Default.DefaultVibrato.VibratoDrift = CurrentVibratoDrift;
NotePresets.Default.DefaultVibrato.VibratoVolLink = CurrentVibratoVolLink;
+ NotePresets.Default.DefaultVibrato.VibratoVariance = CurrentVibratoVariance;
+ NotePresets.Default.DefaultVibrato.VibratoPitchVariance = CurrentVibratoPitchVariance;
+ NotePresets.Default.DefaultVibrato.VibratoVarianceFreq = CurrentVibratoVarianceFreq;
+ NotePresets.Default.DefaultVibrato.VibratoVarianceSeed = CurrentVibratoVarianceSeed;
NotePresets.Save();
}
});
@@ -195,7 +230,7 @@ public void SaveVibratoPreset(string name) {
if (string.IsNullOrEmpty(name)) {
return;
}
- NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, CurrentVibratoLength, CurrentVibratoPeriod, CurrentVibratoDepth, CurrentVibratoIn, CurrentVibratoOut, CurrentVibratoShift, CurrentVibratoDrift, CurrentVibratoVolLink));
+ NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, CurrentVibratoLength, CurrentVibratoPeriod, CurrentVibratoDepth, CurrentVibratoIn, CurrentVibratoOut, CurrentVibratoShift, CurrentVibratoDrift, CurrentVibratoVolLink, CurrentVibratoVariance, CurrentVibratoPitchVariance, CurrentVibratoVarianceFreq, CurrentVibratoVarianceSeed));
NotePresets.Save();
DocManager.Inst.ExecuteCmd(new NotePresetChangedNotification());
}
@@ -222,6 +257,10 @@ public void ResetSettings() {
CurrentVibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
CurrentVibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
CurrentVibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
+ CurrentVibratoVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ CurrentVibratoPitchVariance = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
+ CurrentVibratoVarianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ CurrentVibratoVarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
}
diff --git a/OpenUtau/ViewModels/NotePropertiesViewModel.cs b/OpenUtau/ViewModels/NotePropertiesViewModel.cs
index 38a15d319..e2b797a15 100644
--- a/OpenUtau/ViewModels/NotePropertiesViewModel.cs
+++ b/OpenUtau/ViewModels/NotePropertiesViewModel.cs
@@ -30,6 +30,10 @@ public class NotePropertiesViewModel : ViewModelBase, ICmdSubscriber {
[Reactive] public float VibratoShift { get; set; }
[Reactive] public float VibratoDrift { get; set; }
[Reactive] public float VibratoVolLink { get; set; }
+ [Reactive] public float VarianceDepth { get; set; }
+ [Reactive] public float PitchVarianceDepth { get; set; }
+ [Reactive] public float VarianceFrequency { get; set; }
+ [Reactive] public int VarianceSeed { get; set; }
[Reactive] public float AutoVibratoNoteLength { get; set; }
[Reactive] public bool AutoVibratoToggle { get; set; }
[Reactive] public bool IsNoteSelected { get; set; } = false;
@@ -86,6 +90,10 @@ public NotePropertiesViewModel() {
SetNoteParams("VibratoShift", Math.Max(0, Math.Min(100, vibratoPreset.VibratoShift)));
SetNoteParams("VibratoDrift", Math.Max(-100, Math.Min(100, vibratoPreset.VibratoDrift)));
SetNoteParams("VibratoVolLink", Math.Max(0, Math.Min(100, vibratoPreset.VibratoVolLink)));
+ SetNoteParams("VarianceDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoVariance)));
+ SetNoteParams("PitchVarianceDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoPitchVariance)));
+ SetNoteParams("VarianceFrequency", Math.Max(0.1, Math.Min(8, vibratoPreset.VibratoVarianceFreq)));
+ SetNoteParams("VarianceSeed", vibratoPreset.VibratoVarianceSeed);
PanelControlPressed = false;
DocManager.Inst.EndUndoGroup();
}
@@ -140,6 +148,10 @@ private void OnSelectNotes() {
VibratoShift = note.vibrato.shift;
VibratoDrift = note.vibrato.drift;
VibratoVolLink = note.vibrato.volLink;
+ VarianceDepth = note.vibrato.variance;
+ PitchVarianceDepth = note.vibrato.pitchVariance;
+ VarianceFrequency = note.vibrato.varianceFreq;
+ VarianceSeed = note.vibrato.varianceSeed;
} else {
IsNoteSelected = false;
Lyric = string.Empty;
@@ -157,6 +169,10 @@ private void OnSelectNotes() {
VibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
VibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
VibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
+ VarianceDepth = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ PitchVarianceDepth = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
+ VarianceFrequency = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ VarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
}
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
@@ -286,6 +302,22 @@ public void OnNext(UCommand cmd, bool isUndo) {
VibratoVolLink = note.vibrato.volLink;
this.RaisePropertyChanged(nameof(VibratoVolLink));
}
+ if (cmd is VibratoVarianceDepthCommand || cmd is SetVibratoCommand) {
+ VarianceDepth = note.vibrato.variance;
+ this.RaisePropertyChanged(nameof(VarianceDepth));
+ }
+ if (cmd is VibratoPitchVarianceCommand || cmd is SetVibratoCommand) {
+ PitchVarianceDepth = note.vibrato.pitchVariance;
+ this.RaisePropertyChanged(nameof(PitchVarianceDepth));
+ }
+ if (cmd is VibratoVarianceFrequencyCommand || cmd is SetVibratoCommand) {
+ VarianceFrequency = note.vibrato.varianceFreq;
+ this.RaisePropertyChanged(nameof(VarianceFrequency));
+ }
+ if (cmd is VibratoVarianceSeedCommand || cmd is SetVibratoCommand) {
+ VarianceSeed = note.vibrato.varianceSeed;
+ this.RaisePropertyChanged(nameof(VarianceSeed));
+ }
}
} else if (cmd is ExpCommand) {
if (cmd is PitchExpCommand) {
@@ -475,6 +507,46 @@ public void SetNoteParams(string tag, object? obj) {
foreach (UNote note in selectedNotes) {
DocManager.Inst.ExecuteCmd(new VibratoVolumeLinkCommand(Part, note, value));
}
+ } else if (tag == "VarianceDepth") {
+ float value;
+ if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0 && f <= 4) {
+ value = f;
+ } else {
+ value = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ }
+ foreach (UNote note in selectedNotes) {
+ DocManager.Inst.ExecuteCmd(new VibratoVarianceDepthCommand(Part, note, value));
+ }
+ } else if (tag == "PitchVarianceDepth") {
+ float value;
+ if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0 && f <= 4) {
+ value = f;
+ } else {
+ value = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
+ }
+ foreach (UNote note in selectedNotes) {
+ DocManager.Inst.ExecuteCmd(new VibratoPitchVarianceCommand(Part, note, value));
+ }
+ } else if (tag == "VarianceFrequency") {
+ float value;
+ if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0.1 && f <= 8) {
+ value = f;
+ } else {
+ value = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ }
+ foreach (UNote note in selectedNotes) {
+ DocManager.Inst.ExecuteCmd(new VibratoVarianceFrequencyCommand(Part, note, value));
+ }
+ } else if (tag == "VarianceSeed") {
+ int value;
+ if (obj != null && (obj is int i || int.TryParse(obj.ToString(), out i))) {
+ value = i;
+ } else {
+ value = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ }
+ foreach (UNote note in selectedNotes) {
+ DocManager.Inst.ExecuteCmd(new VibratoVarianceSeedCommand(Part, note, value));
+ }
}
}
}
@@ -504,6 +576,14 @@ public void SetVibratoEnable() {
DocManager.Inst.EndUndoGroup();
}
}
+ public void SetVibratoVarianceSeed(int newSeed) {
+ if(Part != null && selectedNotes.Count > 0) {
+ DocManager.Inst.StartUndoGroup("command.vibrato.edit");
+ UNote first = selectedNotes.First();
+ DocManager.Inst.ExecuteCmd(new VibratoVarianceSeedCommand(Part, first, newSeed));
+ DocManager.Inst.EndUndoGroup();
+ }
+ }
public void SetNumericalExpressionsChanges(string abbr, float? value) {
if (AllowNoteEdit && Part != null && selectedNotes.Count > 0) {
var track = DocManager.Inst.Project.tracks[Part.trackNo];
@@ -546,7 +626,7 @@ public void SaveVibratoPreset(string name) {
if (string.IsNullOrEmpty(name)) {
return;
}
- NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, VibratoLength, VibratoPeriod, VibratoDepth, VibratoIn, VibratoOut, VibratoShift, VibratoDrift, VibratoVolLink));
+ NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, VibratoLength, VibratoPeriod, VibratoDepth, VibratoIn, VibratoOut, VibratoShift, VibratoDrift, VibratoVolLink, VarianceDepth, PitchVarianceDepth, VarianceFrequency, VarianceSeed));
NotePresets.Save();
VibratoPresets = new ObservableCollection(NotePresets.Default.VibratoPresets);
}
diff --git a/OpenUtau/Views/NoteDefaultsDialog.axaml b/OpenUtau/Views/NoteDefaultsDialog.axaml
index 0f8479ad0..d6deb6fef 100644
--- a/OpenUtau/Views/NoteDefaultsDialog.axaml
+++ b/OpenUtau/Views/NoteDefaultsDialog.axaml
@@ -118,6 +118,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 02e12ed7636789602081327dbdd9d644c74648a3 Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Mon, 9 Feb 2026 19:31:38 -0500
Subject: [PATCH 05/10] update UstxYamlTest for new vibrato variance fields
---
OpenUtau.Test/Core/USTx/UstxYamlTest.cs | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/OpenUtau.Test/Core/USTx/UstxYamlTest.cs b/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
index c7d500dce..46e270676 100644
--- a/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
+++ b/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
@@ -22,6 +22,10 @@ public UstxYamlTest(ITestOutputHelper output) {
index = 0,
value = 123,
});
+ note.vibrato.variance = 0.9F;
+ note.vibrato.pitchVariance = 0.4F;
+ note.vibrato.varianceFreq = 1;
+ note.vibrato.varianceSeed = 12;
}
[Fact]
@@ -38,7 +42,7 @@ public void UNoteSerializationTest() {
- {x: -5, y: 0, shape: io}
- {x: 5, y: 0, shape: io}
snap_first: true
-vibrato: {length: 0, period: 175, depth: 25, in: 10, out: 10, shift: 0, drift: 0, vol_link: 0}
+vibrato: {length: 0, period: 175, depth: 25, in: 10, out: 10, shift: 0, drift: 0, vol_link: 0, variance: 0.9, pitch_variance: 0.4, variance_freq: 1, variance_seed: 12}
tuning: 0
phoneme_expressions:
- {index: 0, abbr: vel, value: 123}
@@ -62,6 +66,10 @@ public void UNoteDeserializationTest() {
Assert.NotNull(vel);
Assert.Null(vel.descriptor);
Assert.Equal(123, vel.value);
+ Assert.Equal(0.9F, actual.vibrato.variance);
+ Assert.Equal(0.4F, actual.vibrato.pitchVariance);
+ Assert.Equal(1.0F, actual.vibrato.varianceFreq);
+ Assert.Equal(12, actual.vibrato.varianceSeed);
}
[Fact]
From ca6e2d483ff36e120da778cf1439dac75a73bd8e Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Tue, 10 Feb 2026 14:20:37 -0500
Subject: [PATCH 06/10] refactor all "variance" to "variation"
---
OpenUtau.Core/Commands/NoteCommands.cs | 72 ++++++++--------
OpenUtau.Core/Ustx/UNote.cs | 54 ++++++------
OpenUtau.Core/Util/NotePresets.cs | 18 ++--
OpenUtau.Test/Core/USTx/UstxYamlTest.cs | 18 ++--
OpenUtau/Controls/NotePropertiesControl.axaml | 36 ++++----
.../Controls/NotePropertiesControl.axaml.cs | 6 +-
OpenUtau/Strings/Strings.axaml | 14 +--
OpenUtau/ViewModels/NoteDefaultsViewModel.cs | 64 +++++++-------
.../ViewModels/NotePropertiesViewModel.cs | 86 +++++++++----------
OpenUtau/Views/NoteDefaultsDialog.axaml | 28 +++---
10 files changed, 198 insertions(+), 198 deletions(-)
diff --git a/OpenUtau.Core/Commands/NoteCommands.cs b/OpenUtau.Core/Commands/NoteCommands.cs
index 259607aab..c5f48e79e 100644
--- a/OpenUtau.Core/Commands/NoteCommands.cs
+++ b/OpenUtau.Core/Commands/NoteCommands.cs
@@ -454,110 +454,110 @@ public override void Unexecute() {
}
}
- public class VibratoVarianceDepthCommand : VibratoCommand {
+ public class VibratoVariationDepthCommand : VibratoCommand {
readonly UNote note;
- readonly float newVariance;
- readonly float oldVariance;
+ readonly float newVariation;
+ readonly float oldVariation;
- public VibratoVarianceDepthCommand(UVoicePart part, UNote note, float variance) : base(part, note) {
+ public VibratoVariationDepthCommand(UVoicePart part, UNote note, float variation) : base(part, note) {
this.note = note;
- newVariance = variance;
- oldVariance = note.vibrato.variance;
+ newVariation = variation;
+ oldVariation = note.vibrato.variation;
}
public override string ToString() {
- return "Change vibrato variance depth";
+ return "Change vibrato variation depth";
}
public override void Execute() {
lock (Part) {
- note.vibrato.variance = newVariance;
+ note.vibrato.variation = newVariation;
}
}
public override void Unexecute() {
lock (Part) {
- note.vibrato.variance = oldVariance;
+ note.vibrato.variation = oldVariation;
}
}
}
- public class VibratoPitchVarianceCommand : VibratoCommand {
+ public class VibratoPitchVariationCommand : VibratoCommand {
readonly UNote note;
- readonly float newPitchVariance;
- readonly float oldPitchVariance;
+ readonly float newPitchVariation;
+ readonly float oldPitchVariation;
- public VibratoPitchVarianceCommand(UVoicePart part, UNote note, float pitchVariance) : base(part, note) {
+ public VibratoPitchVariationCommand(UVoicePart part, UNote note, float pitchVariation) : base(part, note) {
this.note = note;
- newPitchVariance = pitchVariance;
- oldPitchVariance = note.vibrato.pitchVariance;
+ newPitchVariation = pitchVariation;
+ oldPitchVariation = note.vibrato.pitchVariation;
}
public override string ToString() {
- return "Change vibrato pitch variance depth";
+ return "Change vibrato pitch variation depth";
}
public override void Execute() {
lock (Part) {
- note.vibrato.pitchVariance = newPitchVariance;
+ note.vibrato.pitchVariation = newPitchVariation;
}
}
public override void Unexecute() {
lock (Part) {
- note.vibrato.pitchVariance = oldPitchVariance;
+ note.vibrato.pitchVariation = oldPitchVariation;
}
}
}
- public class VibratoVarianceFrequencyCommand : VibratoCommand {
+ public class VibratoVariationFrequencyCommand : VibratoCommand {
readonly UNote note;
- readonly float newVarianceFreq;
- readonly float oldVarianceFreq;
+ readonly float newVariationFreq;
+ readonly float oldVariationFreq;
- public VibratoVarianceFrequencyCommand(UVoicePart part, UNote note, float frequency) : base(part, note) {
+ public VibratoVariationFrequencyCommand(UVoicePart part, UNote note, float frequency) : base(part, note) {
this.note = note;
- newVarianceFreq = frequency;
- oldVarianceFreq = note.vibrato.varianceFreq;
+ newVariationFreq = frequency;
+ oldVariationFreq = note.vibrato.variationFreq;
}
public override string ToString() {
- return "Change vibrato variance frequency";
+ return "Change vibrato variation frequency";
}
public override void Execute() {
lock (Part) {
- note.vibrato.varianceFreq = newVarianceFreq;
+ note.vibrato.variationFreq = newVariationFreq;
}
}
public override void Unexecute() {
lock (Part) {
- note.vibrato.varianceFreq = oldVarianceFreq;
+ note.vibrato.variationFreq = oldVariationFreq;
}
}
}
- public class VibratoVarianceSeedCommand : VibratoCommand {
+ public class VibratoVariationSeedCommand : VibratoCommand {
readonly UNote note;
- readonly int newVarianceSeed;
- readonly int oldVarianceSeed;
+ readonly int newVariationSeed;
+ readonly int oldVariationSeed;
- public VibratoVarianceSeedCommand(UVoicePart part, UNote note, int seed) : base(part, note) {
+ public VibratoVariationSeedCommand(UVoicePart part, UNote note, int seed) : base(part, note) {
this.note = note;
- newVarianceSeed = seed;
- oldVarianceSeed = note.vibrato.varianceSeed;
+ newVariationSeed = seed;
+ oldVariationSeed = note.vibrato.variationSeed;
}
public override string ToString() {
- return "Change vibrato variance seed";
+ return "Change vibrato variation seed";
}
public override void Execute() {
lock (Part) {
- note.vibrato.varianceSeed = newVarianceSeed;
+ note.vibrato.variationSeed = newVariationSeed;
}
}
public override void Unexecute() {
lock (Part) {
- note.vibrato.varianceSeed = oldVarianceSeed;
+ note.vibrato.variationSeed = oldVariationSeed;
}
}
}
diff --git a/OpenUtau.Core/Ustx/UNote.cs b/OpenUtau.Core/Ustx/UNote.cs
index c73a7c983..381c34719 100644
--- a/OpenUtau.Core/Ustx/UNote.cs
+++ b/OpenUtau.Core/Ustx/UNote.cs
@@ -282,14 +282,14 @@ public class UVibrato {
float _drift = NotePresets.Default.DefaultVibrato.VibratoDrift;
// Percentage of volume reduction in linkage with vibrato. When this is 100%, volume will be 1.2 times to 0.2 times regardless of depth.
float _volLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
- // Amount of variance in the shape of the vibrato curve.
- float _variance = NotePresets.Default.DefaultVibrato.VibratoVariance;
- // Amount of variance in the intensity of the vibrato curve.
- float _pitchVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
- // Frequency of variance in the shape of the vibrato curve.
- float _varianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
- // Random seed used for vibrato variance
- int _varianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ // Amount of variation in the shape of the vibrato curve.
+ float _variation = NotePresets.Default.DefaultVibrato.VibratoVariation;
+ // Amount of variation in the intensity of the vibrato curve.
+ float _pitchVariation = NotePresets.Default.DefaultVibrato.VibratoVariation;
+ // Frequency of variation in the shape of the vibrato curve.
+ float _variationFreq = NotePresets.Default.DefaultVibrato.VibratoVariationFreq;
+ // Random seed used for vibrato variation
+ int _variationSeed = NotePresets.Default.DefaultVibrato.VibratoVariationSeed;
public float length { get => _length; set => _length = Math.Max(0, Math.Min(100, value)); }
public float period { get => _period; set => _period = Math.Max(5, Math.Min(500, value)); }
@@ -314,10 +314,10 @@ public float @out {
public float drift { get => _drift; set => _drift = Math.Max(-100, Math.Min(100, value)); }
public float volLink { get => _volLink; set => _volLink = Math.Max(-100, Math.Min(100, value)); }
- public float variance { get => _variance; set => _variance = Math.Max(0, Math.Min(2, value)); }
- public float pitchVariance { get => _pitchVariance; set => _pitchVariance = Math.Max(0, Math.Min(2, value)); }
- public float varianceFreq { get => _varianceFreq; set => _varianceFreq = Math.Max(0.1F, Math.Min(8, value)); }
- public int varianceSeed { get => _varianceSeed; set => _varianceSeed = value; }
+ public float variation { get => _variation; set => _variation = Math.Max(0, Math.Min(2, value)); }
+ public float pitchVariation { get => _pitchVariation; set => _pitchVariation = Math.Max(0, Math.Min(2, value)); }
+ public float variationFreq { get => _variationFreq; set => _variationFreq = Math.Max(0.1F, Math.Min(8, value)); }
+ public int variationSeed { get => _variationSeed; set => _variationSeed = value; }
[YamlIgnore] public float NormalizedStart => 1f - length / 100f;
@@ -331,10 +331,10 @@ public UVibrato Clone() {
shift = shift,
drift = drift,
volLink = volLink,
- variance = variance,
- pitchVariance = pitchVariance,
- varianceFreq = varianceFreq,
- varianceSeed = varianceSeed
+ variation = variation,
+ pitchVariation = pitchVariation,
+ variationFreq = variationFreq,
+ variationSeed = variationSeed
};
return result;
}
@@ -357,13 +357,13 @@ public Vector2 Evaluate(float nPos, float nPeriod, UNote note) {
float nOutPos = 1f - nOut;
float t = (nPos - nStart) / nPeriod + shift / 100f;
float y;
- if(variance > 0 || pitchVariance > 0) {
- Noise.Seed = varianceSeed; // setting seed might need optimization
+ if(variation > 0 || pitchVariation > 0) {
+ Noise.Seed = variationSeed; // setting seed might need optimization
// * 0.33F so it has a reasonable base value, it's too much at unity
- float variancePhaseShift = Noise.Generate(t * varianceFreq) * 0.33F;
- Noise.Seed = varianceSeed + 1;
- float pitchNoise = Noise.Generate(t * varianceFreq) * 100 * pitchVariance;
- t += variancePhaseShift * variance;
+ float variationPhaseShift = Noise.Generate(t * variationFreq) * 0.33F;
+ Noise.Seed = variationSeed + 1;
+ float pitchNoise = Noise.Generate(t * variationFreq) * 100 * pitchVariation;
+ t += variationPhaseShift * variation;
float normalizedDepth = 200 * ((depth - 5) / (200 - 5));
y = (float)Math.Sin(2 * Math.PI * t) * depth + (depth / 100 * drift) + (normalizedDepth / 100 * pitchNoise);
} else {
@@ -398,12 +398,12 @@ public float EvaluateVolume(float nPos, float nPeriod) {
}
float t = (nPos - nStart) / nPeriod + shift / 100f;
float reduction;
- if(variance > 0) {
- Noise.Seed = varianceSeed; // setting seed might need optimization
+ if(variation > 0) {
+ Noise.Seed = variationSeed; // setting seed might need optimization
// * 0.33F so it has a reasonable base value, it's too much at unity
- // TODO actually use pitch variance to influence volume link too??
- float variancePhaseShift = Noise.Generate(t * varianceFreq) * 0.33F;
- t += variancePhaseShift * variance;
+ // TODO actually use pitch variation to influence volume link too??
+ float variationPhaseShift = Noise.Generate(t * variationFreq) * 0.33F;
+ t += variationPhaseShift * variation;
reduction = (-(float)Math.Sin(2 * Math.PI * t) / 2 + 0.3f) * volLink / 100;
} else {
reduction = (-(float)Math.Sin(2 * Math.PI * t) / 2 + 0.3f) * volLink / 100;
diff --git a/OpenUtau.Core/Util/NotePresets.cs b/OpenUtau.Core/Util/NotePresets.cs
index b8cefb802..c0dbeff28 100644
--- a/OpenUtau.Core/Util/NotePresets.cs
+++ b/OpenUtau.Core/Util/NotePresets.cs
@@ -91,12 +91,12 @@ public class VibratoPreset {
public float VibratoShift = 0;
public float VibratoDrift = 0;
public float VibratoVolLink = 0;
- public float VibratoVariance = 0;
- public float VibratoPitchVariance = 0;
- public float VibratoVarianceFreq = 1;
- public int VibratoVarianceSeed = 0;
+ public float VibratoVariation = 0;
+ public float VibratoPitchVariation = 0;
+ public float VibratoVariationFreq = 1;
+ public int VibratoVariationSeed = 0;
- public VibratoPreset(string name, float length, float period, float depth, float fadein, float fadeout, float shift, float drift, float volLink, float variance, float pitchVariance, float varianceFrequency, int varianceSeed) {
+ public VibratoPreset(string name, float length, float period, float depth, float fadein, float fadeout, float shift, float drift, float volLink, float variation, float pitchVariation, float variationFrequency, int variationSeed) {
Name = name;
VibratoLength = length;
VibratoPeriod = period;
@@ -106,10 +106,10 @@ public VibratoPreset(string name, float length, float period, float depth, float
VibratoShift = shift;
VibratoDrift = drift;
VibratoVolLink = volLink;
- VibratoVariance = variance;
- VibratoPitchVariance = pitchVariance;
- VibratoVarianceFreq = varianceFrequency;
- VibratoVarianceSeed = varianceSeed;
+ VibratoVariation = variation;
+ VibratoPitchVariation = pitchVariation;
+ VibratoVariationFreq = variationFrequency;
+ VibratoVariationSeed = variationSeed;
}
public VibratoPreset() {}
diff --git a/OpenUtau.Test/Core/USTx/UstxYamlTest.cs b/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
index 46e270676..69c003e20 100644
--- a/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
+++ b/OpenUtau.Test/Core/USTx/UstxYamlTest.cs
@@ -22,10 +22,10 @@ public UstxYamlTest(ITestOutputHelper output) {
index = 0,
value = 123,
});
- note.vibrato.variance = 0.9F;
- note.vibrato.pitchVariance = 0.4F;
- note.vibrato.varianceFreq = 1;
- note.vibrato.varianceSeed = 12;
+ note.vibrato.variation = 0.9F;
+ note.vibrato.pitchVariation = 0.4F;
+ note.vibrato.variationFreq = 1;
+ note.vibrato.variationSeed = 12;
}
[Fact]
@@ -42,7 +42,7 @@ public void UNoteSerializationTest() {
- {x: -5, y: 0, shape: io}
- {x: 5, y: 0, shape: io}
snap_first: true
-vibrato: {length: 0, period: 175, depth: 25, in: 10, out: 10, shift: 0, drift: 0, vol_link: 0, variance: 0.9, pitch_variance: 0.4, variance_freq: 1, variance_seed: 12}
+vibrato: {length: 0, period: 175, depth: 25, in: 10, out: 10, shift: 0, drift: 0, vol_link: 0, variation: 0.9, pitch_variation: 0.4, variation_freq: 1, variation_seed: 12}
tuning: 0
phoneme_expressions:
- {index: 0, abbr: vel, value: 123}
@@ -66,10 +66,10 @@ public void UNoteDeserializationTest() {
Assert.NotNull(vel);
Assert.Null(vel.descriptor);
Assert.Equal(123, vel.value);
- Assert.Equal(0.9F, actual.vibrato.variance);
- Assert.Equal(0.4F, actual.vibrato.pitchVariance);
- Assert.Equal(1.0F, actual.vibrato.varianceFreq);
- Assert.Equal(12, actual.vibrato.varianceSeed);
+ Assert.Equal(0.9F, actual.vibrato.variation);
+ Assert.Equal(0.4F, actual.vibrato.pitchVariation);
+ Assert.Equal(1.0F, actual.vibrato.variationFreq);
+ Assert.Equal(12, actual.vibrato.variationSeed);
}
[Fact]
diff --git a/OpenUtau/Controls/NotePropertiesControl.axaml b/OpenUtau/Controls/NotePropertiesControl.axaml
index 92d979e4b..c80e8cf98 100644
--- a/OpenUtau/Controls/NotePropertiesControl.axaml
+++ b/OpenUtau/Controls/NotePropertiesControl.axaml
@@ -147,33 +147,33 @@
Tag="VibratoVolLink"/>
-
-
-
+
+
+ Tag="VariationDepth"
+ ToolTip.Tip="{DynamicResource notedefaults.vibrato.variationdepth.tooltip}"/>
-
-
-
+
+
+ Tag="PitchVariationDepth"
+ ToolTip.Tip="{DynamicResource notedefaults.vibrato.pitchvariationdepth.tooltip}"/>
-
-
-
+
+
+ Tag="VariationFrequency"/>
-
-
-
+
+
+
diff --git a/OpenUtau/Controls/NotePropertiesControl.axaml.cs b/OpenUtau/Controls/NotePropertiesControl.axaml.cs
index d8333155b..060afb3ae 100644
--- a/OpenUtau/Controls/NotePropertiesControl.axaml.cs
+++ b/OpenUtau/Controls/NotePropertiesControl.axaml.cs
@@ -137,10 +137,10 @@ void OnSaveVibratoPreset(object sender, RoutedEventArgs e) {
}
}
- void OnNewVarianceSeed(object sender, RoutedEventArgs e) {
+ void OnNewVariationSeed(object sender, RoutedEventArgs e) {
int newSeed = Random.Shared.Next();
- ViewModel.SetVibratoVarianceSeed(newSeed);
- ViewModel.VarianceSeed = newSeed;
+ ViewModel.SetVibratoVariationSeed(newSeed);
+ ViewModel.VariationSeed = newSeed;
}
void OnRemoveVibratoPreset(object sender, RoutedEventArgs e) {
diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml
index d22e81b88..c43c53436 100644
--- a/OpenUtau/Strings/Strings.axaml
+++ b/OpenUtau/Strings/Strings.axaml
@@ -334,13 +334,13 @@ Warning: this option removes custom presets.
Period
Shift
Volume Link
- Variance
- Depth Variance
- Variance Seed
- Variance Frequency
- New Seed
- Amount of random variation in the shape of the vibrato curve. At 0, this setting has no effect on the vibrato.
- Amount of random variation in the intensity of vibrato. This setting is independent of Variance, but inherits the Variance Seed and Variance Frequency settings. At 0, this setting has no effect on the vibrato.
+ Variation
+ Depth Variation
+ Variation Seed
+ Variation Frequency
+ New Seed
+ Amount of random variation in the shape of the vibrato curve. At 0, this setting has no effect on the vibrato.
+ Amount of random variation in the intensity of vibrato. This setting is independent of Variation, but inherits the Variation Seed and Variation Frequency settings. At 0, this setting has no effect on the vibrato.
Note Properties
Apply
diff --git a/OpenUtau/ViewModels/NoteDefaultsViewModel.cs b/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
index 79de42273..03a9a3a17 100644
--- a/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
+++ b/OpenUtau/ViewModels/NoteDefaultsViewModel.cs
@@ -21,10 +21,10 @@ class NoteDefaultsViewModel : ViewModelBase {
[Reactive] public float CurrentVibratoShift { get; set; }
[Reactive] public float CurrentVibratoDrift { get; set; }
[Reactive] public float CurrentVibratoVolLink { get; set; }
- [Reactive] public float CurrentVibratoVariance { get; set; }
- [Reactive] public float CurrentVibratoPitchVariance { get; set; }
- [Reactive] public float CurrentVibratoVarianceFreq { get; set; }
- [Reactive] public int CurrentVibratoVarianceSeed { get; set; }
+ [Reactive] public float CurrentVibratoVariation { get; set; }
+ [Reactive] public float CurrentVibratoPitchVariation { get; set; }
+ [Reactive] public float CurrentVibratoVariationFreq { get; set; }
+ [Reactive] public int CurrentVibratoVariationSeed { get; set; }
[Reactive] public float AutoVibratoNoteLength { get; set; }
[Reactive] public bool AutoVibratoToggle { get; set; }
public List? PortamentoPresets { get; }
@@ -56,9 +56,9 @@ public NoteDefaultsViewModel() {
CurrentVibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
CurrentVibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
CurrentVibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
- CurrentVibratoVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
- CurrentVibratoVarianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
- CurrentVibratoVarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ CurrentVibratoVariation = NotePresets.Default.DefaultVibrato.VibratoVariation;
+ CurrentVibratoVariationFreq = NotePresets.Default.DefaultVibrato.VibratoVariationFreq;
+ CurrentVibratoVariationSeed = NotePresets.Default.DefaultVibrato.VibratoVariationSeed;
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
PortamentoPresets = NotePresets.Default.PortamentoPresets;
@@ -134,24 +134,24 @@ public NoteDefaultsViewModel() {
NotePresets.Default.DefaultVibrato.VibratoVolLink = Math.Max(-100, Math.Min(100, vibratoVolLink));
NotePresets.Save();
});
- this.WhenAnyValue(vm => vm.CurrentVibratoVariance)
- .Subscribe(vibratoVariance => {
- NotePresets.Default.DefaultVibrato.VibratoVariance = Math.Max(0, Math.Min(4, vibratoVariance));
+ this.WhenAnyValue(vm => vm.CurrentVibratoVariation)
+ .Subscribe(vibratoVariation => {
+ NotePresets.Default.DefaultVibrato.VibratoVariation = Math.Max(0, Math.Min(4, vibratoVariation));
NotePresets.Save();
});
- this.WhenAnyValue(vm => vm.CurrentVibratoPitchVariance)
- .Subscribe(vibratoPitchVariance => {
- NotePresets.Default.DefaultVibrato.VibratoPitchVariance = Math.Max(0, Math.Min(4, vibratoPitchVariance));
+ this.WhenAnyValue(vm => vm.CurrentVibratoPitchVariation)
+ .Subscribe(vibratoPitchVariation => {
+ NotePresets.Default.DefaultVibrato.VibratoPitchVariation = Math.Max(0, Math.Min(4, vibratoPitchVariation));
NotePresets.Save();
});
- this.WhenAnyValue(vm => vm.CurrentVibratoVarianceFreq)
- .Subscribe(vibratoVarianceFreq => {
- NotePresets.Default.DefaultVibrato.VibratoVarianceFreq = Math.Max(0.1F, Math.Min(8, vibratoVarianceFreq));
+ this.WhenAnyValue(vm => vm.CurrentVibratoVariationFreq)
+ .Subscribe(vibratoVariationFreq => {
+ NotePresets.Default.DefaultVibrato.VibratoVariationFreq = Math.Max(0.1F, Math.Min(8, vibratoVariationFreq));
NotePresets.Save();
});
- this.WhenAnyValue(vm => vm.CurrentVibratoVarianceSeed)
- .Subscribe(vibratoVarianceSeed => {
- NotePresets.Default.DefaultVibrato.VibratoVarianceSeed = vibratoVarianceSeed;
+ this.WhenAnyValue(vm => vm.CurrentVibratoVariationSeed)
+ .Subscribe(vibratoVariationSeed => {
+ NotePresets.Default.DefaultVibrato.VibratoVariationSeed = vibratoVariationSeed;
NotePresets.Save();
});
this.WhenAnyValue(vm => vm.AutoVibratoToggle)
@@ -187,10 +187,10 @@ public NoteDefaultsViewModel() {
CurrentVibratoShift = Math.Max(0, Math.Min(100, vibratoPreset.VibratoShift));
CurrentVibratoDrift = Math.Max(-100, Math.Min(100, vibratoPreset.VibratoDrift));
CurrentVibratoVolLink = Math.Max(-100, Math.Min(100, vibratoPreset.VibratoVolLink));
- CurrentVibratoVariance = Math.Max(0, Math.Min(4, vibratoPreset.VibratoVariance));
- CurrentVibratoPitchVariance = Math.Max(0, Math.Min(4, vibratoPreset.VibratoPitchVariance));
- CurrentVibratoVarianceFreq = Math.Max(0.1F, Math.Min(8, vibratoPreset.VibratoVarianceFreq));
- CurrentVibratoVarianceSeed = vibratoPreset.VibratoVarianceSeed;
+ CurrentVibratoVariation = Math.Max(0, Math.Min(4, vibratoPreset.VibratoVariation));
+ CurrentVibratoPitchVariation = Math.Max(0, Math.Min(4, vibratoPreset.VibratoPitchVariation));
+ CurrentVibratoVariationFreq = Math.Max(0.1F, Math.Min(8, vibratoPreset.VibratoVariationFreq));
+ CurrentVibratoVariationSeed = vibratoPreset.VibratoVariationSeed;
NotePresets.Default.DefaultVibrato.VibratoLength = CurrentVibratoLength;
NotePresets.Default.DefaultVibrato.VibratoPeriod = CurrentVibratoPeriod;
NotePresets.Default.DefaultVibrato.VibratoDepth = CurrentVibratoDepth;
@@ -199,10 +199,10 @@ public NoteDefaultsViewModel() {
NotePresets.Default.DefaultVibrato.VibratoShift = CurrentVibratoShift;
NotePresets.Default.DefaultVibrato.VibratoDrift = CurrentVibratoDrift;
NotePresets.Default.DefaultVibrato.VibratoVolLink = CurrentVibratoVolLink;
- NotePresets.Default.DefaultVibrato.VibratoVariance = CurrentVibratoVariance;
- NotePresets.Default.DefaultVibrato.VibratoPitchVariance = CurrentVibratoPitchVariance;
- NotePresets.Default.DefaultVibrato.VibratoVarianceFreq = CurrentVibratoVarianceFreq;
- NotePresets.Default.DefaultVibrato.VibratoVarianceSeed = CurrentVibratoVarianceSeed;
+ NotePresets.Default.DefaultVibrato.VibratoVariation = CurrentVibratoVariation;
+ NotePresets.Default.DefaultVibrato.VibratoPitchVariation = CurrentVibratoPitchVariation;
+ NotePresets.Default.DefaultVibrato.VibratoVariationFreq = CurrentVibratoVariationFreq;
+ NotePresets.Default.DefaultVibrato.VibratoVariationSeed = CurrentVibratoVariationSeed;
NotePresets.Save();
}
});
@@ -230,7 +230,7 @@ public void SaveVibratoPreset(string name) {
if (string.IsNullOrEmpty(name)) {
return;
}
- NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, CurrentVibratoLength, CurrentVibratoPeriod, CurrentVibratoDepth, CurrentVibratoIn, CurrentVibratoOut, CurrentVibratoShift, CurrentVibratoDrift, CurrentVibratoVolLink, CurrentVibratoVariance, CurrentVibratoPitchVariance, CurrentVibratoVarianceFreq, CurrentVibratoVarianceSeed));
+ NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, CurrentVibratoLength, CurrentVibratoPeriod, CurrentVibratoDepth, CurrentVibratoIn, CurrentVibratoOut, CurrentVibratoShift, CurrentVibratoDrift, CurrentVibratoVolLink, CurrentVibratoVariation, CurrentVibratoPitchVariation, CurrentVibratoVariationFreq, CurrentVibratoVariationSeed));
NotePresets.Save();
DocManager.Inst.ExecuteCmd(new NotePresetChangedNotification());
}
@@ -257,10 +257,10 @@ public void ResetSettings() {
CurrentVibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
CurrentVibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
CurrentVibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
- CurrentVibratoVariance = NotePresets.Default.DefaultVibrato.VibratoVariance;
- CurrentVibratoPitchVariance = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
- CurrentVibratoVarianceFreq = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
- CurrentVibratoVarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ CurrentVibratoVariation = NotePresets.Default.DefaultVibrato.VibratoVariation;
+ CurrentVibratoPitchVariation = NotePresets.Default.DefaultVibrato.VibratoPitchVariation;
+ CurrentVibratoVariationFreq = NotePresets.Default.DefaultVibrato.VibratoVariationFreq;
+ CurrentVibratoVariationSeed = NotePresets.Default.DefaultVibrato.VibratoVariationSeed;
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
}
diff --git a/OpenUtau/ViewModels/NotePropertiesViewModel.cs b/OpenUtau/ViewModels/NotePropertiesViewModel.cs
index e2b797a15..0b86794ce 100644
--- a/OpenUtau/ViewModels/NotePropertiesViewModel.cs
+++ b/OpenUtau/ViewModels/NotePropertiesViewModel.cs
@@ -30,10 +30,10 @@ public class NotePropertiesViewModel : ViewModelBase, ICmdSubscriber {
[Reactive] public float VibratoShift { get; set; }
[Reactive] public float VibratoDrift { get; set; }
[Reactive] public float VibratoVolLink { get; set; }
- [Reactive] public float VarianceDepth { get; set; }
- [Reactive] public float PitchVarianceDepth { get; set; }
- [Reactive] public float VarianceFrequency { get; set; }
- [Reactive] public int VarianceSeed { get; set; }
+ [Reactive] public float VariationDepth { get; set; }
+ [Reactive] public float PitchVariationDepth { get; set; }
+ [Reactive] public float VariationFrequency { get; set; }
+ [Reactive] public int VariationSeed { get; set; }
[Reactive] public float AutoVibratoNoteLength { get; set; }
[Reactive] public bool AutoVibratoToggle { get; set; }
[Reactive] public bool IsNoteSelected { get; set; } = false;
@@ -90,10 +90,10 @@ public NotePropertiesViewModel() {
SetNoteParams("VibratoShift", Math.Max(0, Math.Min(100, vibratoPreset.VibratoShift)));
SetNoteParams("VibratoDrift", Math.Max(-100, Math.Min(100, vibratoPreset.VibratoDrift)));
SetNoteParams("VibratoVolLink", Math.Max(0, Math.Min(100, vibratoPreset.VibratoVolLink)));
- SetNoteParams("VarianceDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoVariance)));
- SetNoteParams("PitchVarianceDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoPitchVariance)));
- SetNoteParams("VarianceFrequency", Math.Max(0.1, Math.Min(8, vibratoPreset.VibratoVarianceFreq)));
- SetNoteParams("VarianceSeed", vibratoPreset.VibratoVarianceSeed);
+ SetNoteParams("VariationDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoVariation)));
+ SetNoteParams("PitchVariationDepth", Math.Max(0, Math.Min(2, vibratoPreset.VibratoPitchVariation)));
+ SetNoteParams("VariationFrequency", Math.Max(0.1, Math.Min(8, vibratoPreset.VibratoVariationFreq)));
+ SetNoteParams("VariationSeed", vibratoPreset.VibratoVariationSeed);
PanelControlPressed = false;
DocManager.Inst.EndUndoGroup();
}
@@ -148,10 +148,10 @@ private void OnSelectNotes() {
VibratoShift = note.vibrato.shift;
VibratoDrift = note.vibrato.drift;
VibratoVolLink = note.vibrato.volLink;
- VarianceDepth = note.vibrato.variance;
- PitchVarianceDepth = note.vibrato.pitchVariance;
- VarianceFrequency = note.vibrato.varianceFreq;
- VarianceSeed = note.vibrato.varianceSeed;
+ VariationDepth = note.vibrato.variation;
+ PitchVariationDepth = note.vibrato.pitchVariation;
+ VariationFrequency = note.vibrato.variationFreq;
+ VariationSeed = note.vibrato.variationSeed;
} else {
IsNoteSelected = false;
Lyric = string.Empty;
@@ -169,10 +169,10 @@ private void OnSelectNotes() {
VibratoShift = NotePresets.Default.DefaultVibrato.VibratoShift;
VibratoDrift = NotePresets.Default.DefaultVibrato.VibratoDrift;
VibratoVolLink = NotePresets.Default.DefaultVibrato.VibratoVolLink;
- VarianceDepth = NotePresets.Default.DefaultVibrato.VibratoVariance;
- PitchVarianceDepth = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
- VarianceFrequency = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
- VarianceSeed = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ VariationDepth = NotePresets.Default.DefaultVibrato.VibratoVariation;
+ PitchVariationDepth = NotePresets.Default.DefaultVibrato.VibratoPitchVariation;
+ VariationFrequency = NotePresets.Default.DefaultVibrato.VibratoVariationFreq;
+ VariationSeed = NotePresets.Default.DefaultVibrato.VibratoVariationSeed;
}
AutoVibratoNoteLength = NotePresets.Default.AutoVibratoNoteDuration;
AutoVibratoToggle = NotePresets.Default.AutoVibratoToggle;
@@ -302,21 +302,21 @@ public void OnNext(UCommand cmd, bool isUndo) {
VibratoVolLink = note.vibrato.volLink;
this.RaisePropertyChanged(nameof(VibratoVolLink));
}
- if (cmd is VibratoVarianceDepthCommand || cmd is SetVibratoCommand) {
- VarianceDepth = note.vibrato.variance;
- this.RaisePropertyChanged(nameof(VarianceDepth));
+ if (cmd is VibratoVariationDepthCommand || cmd is SetVibratoCommand) {
+ VariationDepth = note.vibrato.variation;
+ this.RaisePropertyChanged(nameof(VariationDepth));
}
- if (cmd is VibratoPitchVarianceCommand || cmd is SetVibratoCommand) {
- PitchVarianceDepth = note.vibrato.pitchVariance;
- this.RaisePropertyChanged(nameof(PitchVarianceDepth));
+ if (cmd is VibratoPitchVariationCommand || cmd is SetVibratoCommand) {
+ PitchVariationDepth = note.vibrato.pitchVariation;
+ this.RaisePropertyChanged(nameof(PitchVariationDepth));
}
- if (cmd is VibratoVarianceFrequencyCommand || cmd is SetVibratoCommand) {
- VarianceFrequency = note.vibrato.varianceFreq;
- this.RaisePropertyChanged(nameof(VarianceFrequency));
+ if (cmd is VibratoVariationFrequencyCommand || cmd is SetVibratoCommand) {
+ VariationFrequency = note.vibrato.variationFreq;
+ this.RaisePropertyChanged(nameof(VariationFrequency));
}
- if (cmd is VibratoVarianceSeedCommand || cmd is SetVibratoCommand) {
- VarianceSeed = note.vibrato.varianceSeed;
- this.RaisePropertyChanged(nameof(VarianceSeed));
+ if (cmd is VibratoVariationSeedCommand || cmd is SetVibratoCommand) {
+ VariationSeed = note.vibrato.variationSeed;
+ this.RaisePropertyChanged(nameof(VariationSeed));
}
}
} else if (cmd is ExpCommand) {
@@ -507,45 +507,45 @@ public void SetNoteParams(string tag, object? obj) {
foreach (UNote note in selectedNotes) {
DocManager.Inst.ExecuteCmd(new VibratoVolumeLinkCommand(Part, note, value));
}
- } else if (tag == "VarianceDepth") {
+ } else if (tag == "VariationDepth") {
float value;
if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0 && f <= 4) {
value = f;
} else {
- value = NotePresets.Default.DefaultVibrato.VibratoVariance;
+ value = NotePresets.Default.DefaultVibrato.VibratoVariation;
}
foreach (UNote note in selectedNotes) {
- DocManager.Inst.ExecuteCmd(new VibratoVarianceDepthCommand(Part, note, value));
+ DocManager.Inst.ExecuteCmd(new VibratoVariationDepthCommand(Part, note, value));
}
- } else if (tag == "PitchVarianceDepth") {
+ } else if (tag == "PitchVariationDepth") {
float value;
if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0 && f <= 4) {
value = f;
} else {
- value = NotePresets.Default.DefaultVibrato.VibratoPitchVariance;
+ value = NotePresets.Default.DefaultVibrato.VibratoPitchVariation;
}
foreach (UNote note in selectedNotes) {
- DocManager.Inst.ExecuteCmd(new VibratoPitchVarianceCommand(Part, note, value));
+ DocManager.Inst.ExecuteCmd(new VibratoPitchVariationCommand(Part, note, value));
}
- } else if (tag == "VarianceFrequency") {
+ } else if (tag == "VariationFrequency") {
float value;
if (obj != null && (obj is float f || float.TryParse(obj.ToString(), out f)) && f >= 0.1 && f <= 8) {
value = f;
} else {
- value = NotePresets.Default.DefaultVibrato.VibratoVarianceFreq;
+ value = NotePresets.Default.DefaultVibrato.VibratoVariationFreq;
}
foreach (UNote note in selectedNotes) {
- DocManager.Inst.ExecuteCmd(new VibratoVarianceFrequencyCommand(Part, note, value));
+ DocManager.Inst.ExecuteCmd(new VibratoVariationFrequencyCommand(Part, note, value));
}
- } else if (tag == "VarianceSeed") {
+ } else if (tag == "VariationSeed") {
int value;
if (obj != null && (obj is int i || int.TryParse(obj.ToString(), out i))) {
value = i;
} else {
- value = NotePresets.Default.DefaultVibrato.VibratoVarianceSeed;
+ value = NotePresets.Default.DefaultVibrato.VibratoVariationSeed;
}
foreach (UNote note in selectedNotes) {
- DocManager.Inst.ExecuteCmd(new VibratoVarianceSeedCommand(Part, note, value));
+ DocManager.Inst.ExecuteCmd(new VibratoVariationSeedCommand(Part, note, value));
}
}
}
@@ -576,11 +576,11 @@ public void SetVibratoEnable() {
DocManager.Inst.EndUndoGroup();
}
}
- public void SetVibratoVarianceSeed(int newSeed) {
+ public void SetVibratoVariationSeed(int newSeed) {
if(Part != null && selectedNotes.Count > 0) {
DocManager.Inst.StartUndoGroup("command.vibrato.edit");
UNote first = selectedNotes.First();
- DocManager.Inst.ExecuteCmd(new VibratoVarianceSeedCommand(Part, first, newSeed));
+ DocManager.Inst.ExecuteCmd(new VibratoVariationSeedCommand(Part, first, newSeed));
DocManager.Inst.EndUndoGroup();
}
}
@@ -626,7 +626,7 @@ public void SaveVibratoPreset(string name) {
if (string.IsNullOrEmpty(name)) {
return;
}
- NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, VibratoLength, VibratoPeriod, VibratoDepth, VibratoIn, VibratoOut, VibratoShift, VibratoDrift, VibratoVolLink, VarianceDepth, PitchVarianceDepth, VarianceFrequency, VarianceSeed));
+ NotePresets.Default.VibratoPresets.Add(new NotePresets.VibratoPreset(name, VibratoLength, VibratoPeriod, VibratoDepth, VibratoIn, VibratoOut, VibratoShift, VibratoDrift, VibratoVolLink, VariationDepth, PitchVariationDepth, VariationFrequency, VariationSeed));
NotePresets.Save();
VibratoPresets = new ObservableCollection(NotePresets.Default.VibratoPresets);
}
diff --git a/OpenUtau/Views/NoteDefaultsDialog.axaml b/OpenUtau/Views/NoteDefaultsDialog.axaml
index d6deb6fef..eb715249a 100644
--- a/OpenUtau/Views/NoteDefaultsDialog.axaml
+++ b/OpenUtau/Views/NoteDefaultsDialog.axaml
@@ -119,27 +119,27 @@
TickPlacement="BottomRight" TickFrequency="0.1" IsSnapToTickEnabled="true" />
-
-
-
+
+
+ Tag="CurrentVibratoVariation"
+ ToolTip.Tip="{DynamicResource notedefaults.vibrato.variationdepth.tooltip}"/>
-
-
-
+
+
+ Tag="CurrentVibratoPitchVariation"
+ ToolTip.Tip="{DynamicResource notedefaults.vibrato.pitchvariationdepth.tooltip}"/>
-
-
-
+
+
+ Tag="CurrentVibratoVariationFreq"/>
From 178cd71a9e35602c3c8b76975e11d07e6a1732af Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Wed, 11 Feb 2026 13:44:09 -0500
Subject: [PATCH 07/10] "Randomize pitch deviation" batch edit
---
OpenUtau.Core/Editing/NoteBatchEdits.cs | 81 +++++++++++++++++++++++++
OpenUtau/Controls/PianoRoll.axaml.cs | 38 ++++++++++++
OpenUtau/Strings/Strings.axaml | 2 +-
3 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/OpenUtau.Core/Editing/NoteBatchEdits.cs b/OpenUtau.Core/Editing/NoteBatchEdits.cs
index 4c3114876..d06e18237 100644
--- a/OpenUtau.Core/Editing/NoteBatchEdits.cs
+++ b/OpenUtau.Core/Editing/NoteBatchEdits.cs
@@ -4,6 +4,7 @@
using System.Threading;
using OpenUtau.Core.Ustx;
using OpenUtau.Core.Format;
+using SimplexNoise;
namespace OpenUtau.Core.Editing {
public class AddTailNote : BatchEdit {
@@ -446,6 +447,86 @@ public void Run(UProject project, UVoicePart part, List selectedNotes, Do
}
}
+ public class RandomPitchDeviation : BatchEdit {
+ public virtual string Name => name;
+ private string name;
+ public float noiseScale;
+ public float noiseFrequency;
+
+ public RandomPitchDeviation(float noiseScale, float noiseFrequency) {
+ name = "pianoroll.menu.notes.randompitd";
+ this.noiseScale = noiseScale;
+ this.noiseFrequency = noiseFrequency;
+ }
+
+ public void Run(UProject project, UVoicePart part, List selectedNotes, DocManager docManager) {
+ if (selectedNotes.Count == 0) {
+ return;
+ }
+ docManager.StartUndoGroup("command.batch.note", true);
+
+ Random random = new Random();
+ int seed = random.Next();
+ int numOctaves = 4;
+ float baseScale = 0.25F;
+ float coarseFrequency = 0.001F;
+
+ var positions = selectedNotes.Select(n => n.position + part.position).ToHashSet();
+ var phrases = part.renderPhrases.Where(phrase => phrase.notes.Any(n => positions.Contains(phrase.position + n.position))).ToArray();
+
+ var pitdCurve = part.curves.Find(c => c.abbr.Equals(Format.Ustx.PITD));
+ if (pitdCurve == null) {
+ // hmmm...
+ if (project.expressions.TryGetValue(Format.Ustx.PITD, out var descriptor)) {
+ pitdCurve = new UCurve(descriptor);
+ part.curves.Add(pitdCurve);
+ }
+ }
+
+ foreach (var phrase in phrases) {
+ var start = phrase.position;
+ var end = phrase.end;
+ int numSamples = phrase.duration;
+
+ float[] noiseSum = new float[numSamples];
+ Array.Fill(noiseSum, 0);
+
+ // when summing together the noise values in this manner
+ // 510 is the highest possible sum (for values generated by Calc1D, [0, 255]).
+ // multiplying by (1 - 0.5 ^ numOctaves) calculates
+ // the precise highest value based on the number of octaves
+
+ // i wanted to have a dialog for changing octaves and seed but that would be too
+ // many single dialogs for a user to have to click through, IMO
+ float highestValue = 510 * (1 - (float)Math.Pow(0.5, numOctaves));
+ for (int i = 0; i < numOctaves; i++) {
+ Noise.Seed = seed;
+
+ float octaveInfluence = (float)Math.Pow(2, i);
+ float octaveFrequency = (coarseFrequency * noiseFrequency) * (4 * octaveInfluence);
+ float[] noise = Noise.Calc1D(numSamples, octaveFrequency);
+ for (int j = 0; j < noise.Length; j++) {
+ noiseSum[j] += noise[j] / octaveInfluence;
+ }
+
+ seed = random.Next();
+ }
+
+ for (int i = 0; i < noiseSum.Length; i++) {
+ float curveValue = pitdCurve.Sample(start + i);
+ float noiseValue = (noiseSum[i] - (highestValue / 2)) * baseScale;
+ curveValue += (int)Math.Round(noiseValue * noiseScale);
+ docManager.ExecuteCmd(new SetCurveCommand(project, part, Format.Ustx.PITD,
+ start + i, (int)curveValue,
+ start + i, 0
+ ));
+ }
+ }
+
+ docManager.EndUndoGroup();
+ }
+ }
+
public class LoadRenderedPitch : BatchEdit {
public virtual string Name => name;
diff --git a/OpenUtau/Controls/PianoRoll.axaml.cs b/OpenUtau/Controls/PianoRoll.axaml.cs
index 4d3ba7bfc..d1bbe2a99 100644
--- a/OpenUtau/Controls/PianoRoll.axaml.cs
+++ b/OpenUtau/Controls/PianoRoll.axaml.cs
@@ -163,6 +163,12 @@ await MessageBox.ShowProcessing(RootWindow, $"{name} - ? / ?",
RandomizeTuning();
})
});
+ ViewModel.NoteBatchEdits.Add(new MenuItemViewModel() {
+ Header = ThemeManager.GetString("pianoroll.menu.notes.randompitd"),
+ Command = ReactiveCommand.Create(() => {
+ RandomizePitchDeviation();
+ })
+ });
ViewModel.NoteBatchEdits.Add(new MenuItemViewModel() {
Header = ThemeManager.GetString("pianoroll.menu.notes.lengthencrossfade"),
Command = ReactiveCommand.Create(() => {
@@ -434,6 +440,38 @@ void RandomizeTuning() {
dialog.ShowDialog(RootWindow);
}
+ void RandomizePitchDeviation() {
+ var notesVM = ViewModel.NotesViewModel;
+ if (notesVM.Part == null) {
+ return;
+ }
+ if (notesVM.Selection.IsEmpty) {
+ _ = MessageBox.Show(
+ RootWindow,
+ ThemeManager.GetString("lyrics.selectnotes"),
+ ThemeManager.GetString("lyrics.caption"),
+ MessageBox.MessageBoxButtons.Ok);
+ return;
+ }
+
+ var scaleDialog = new SliderDialog("Random Scale", 1, 0, 2, 0.01);
+ scaleDialog.onFinish = scale => {
+ // want multi-control dialogs
+ var freqDialog = new SliderDialog("Random Frequency", 1, 0.1, 6, 0.1);
+ freqDialog.onFinish = freq => {
+ try {
+ var edit = new RandomPitchDeviation((float)scale, (float)freq);
+ edit.Run(notesVM.Project, notesVM.Part, notesVM.Selection.ToList(), DocManager.Inst);
+ } catch (Exception e) {
+ var customEx = new MessageCustomizableException("Failed to run editing macro", "", e);
+ DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
+ }
+ };
+ freqDialog.ShowDialog(RootWindow);
+ };
+ scaleDialog.ShowDialog(RootWindow);
+ }
+
void LengthenCrossfade() {
var notesVM = ViewModel.NotesViewModel;
if (notesVM.Part == null) {
diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml
index c43c53436..bc28d8ea3 100644
--- a/OpenUtau/Strings/Strings.axaml
+++ b/OpenUtau/Strings/Strings.axaml
@@ -444,7 +444,7 @@ Warning: this option removes custom presets.
Randomize phoneme offset
Randomize note timing
Randomize tuning
- Randomize pitch deviation
+ Randomize pitch deviation
Refresh real curves
Remove tail "-"
Remove tail "R"
From f85e0dd27a54dacda215e357d7d923e4516d6284 Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Wed, 11 Feb 2026 13:47:29 -0500
Subject: [PATCH 08/10] make curveValue an int
---
OpenUtau.Core/Editing/NoteBatchEdits.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/OpenUtau.Core/Editing/NoteBatchEdits.cs b/OpenUtau.Core/Editing/NoteBatchEdits.cs
index d06e18237..b2eeb2934 100644
--- a/OpenUtau.Core/Editing/NoteBatchEdits.cs
+++ b/OpenUtau.Core/Editing/NoteBatchEdits.cs
@@ -513,11 +513,11 @@ public void Run(UProject project, UVoicePart part, List selectedNotes, Do
}
for (int i = 0; i < noiseSum.Length; i++) {
- float curveValue = pitdCurve.Sample(start + i);
+ int curveValue = pitdCurve.Sample(start + i);
float noiseValue = (noiseSum[i] - (highestValue / 2)) * baseScale;
curveValue += (int)Math.Round(noiseValue * noiseScale);
docManager.ExecuteCmd(new SetCurveCommand(project, part, Format.Ustx.PITD,
- start + i, (int)curveValue,
+ start + i, curveValue,
start + i, 0
));
}
From a9c3e7a6ab5b5344f485d723e381142dbe5dd1ee Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Wed, 11 Feb 2026 14:41:34 -0500
Subject: [PATCH 09/10] random variation seed on note creation
---
OpenUtau.Core/Ustx/UProject.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/OpenUtau.Core/Ustx/UProject.cs b/OpenUtau.Core/Ustx/UProject.cs
index 462f2a513..b63c27bbf 100644
--- a/OpenUtau.Core/Ustx/UProject.cs
+++ b/OpenUtau.Core/Ustx/UProject.cs
@@ -121,6 +121,7 @@ public UNote CreateNote() {
int length = NotePresets.Default.DefaultPortamento.PortamentoLength;
note.pitch.AddPoint(new PitchPoint(start, 0));
note.pitch.AddPoint(new PitchPoint(start + length, 0));
+ note.vibrato.variationSeed = Random.Shared.Next();
return note;
}
From 605a616ccf80de54174e8478a58b705713717053 Mon Sep 17 00:00:00 2001
From: p4o-a7o <94420131+p4o-a7o@users.noreply.github.com>
Date: Wed, 11 Feb 2026 15:08:13 -0500
Subject: [PATCH 10/10] edit pitch deviation per-note
---
OpenUtau.Core/Editing/NoteBatchEdits.cs | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/OpenUtau.Core/Editing/NoteBatchEdits.cs b/OpenUtau.Core/Editing/NoteBatchEdits.cs
index b2eeb2934..31e0334ff 100644
--- a/OpenUtau.Core/Editing/NoteBatchEdits.cs
+++ b/OpenUtau.Core/Editing/NoteBatchEdits.cs
@@ -471,9 +471,6 @@ public void Run(UProject project, UVoicePart part, List selectedNotes, Do
float baseScale = 0.25F;
float coarseFrequency = 0.001F;
- var positions = selectedNotes.Select(n => n.position + part.position).ToHashSet();
- var phrases = part.renderPhrases.Where(phrase => phrase.notes.Any(n => positions.Contains(phrase.position + n.position))).ToArray();
-
var pitdCurve = part.curves.Find(c => c.abbr.Equals(Format.Ustx.PITD));
if (pitdCurve == null) {
// hmmm...
@@ -483,10 +480,10 @@ public void Run(UProject project, UVoicePart part, List selectedNotes, Do
}
}
- foreach (var phrase in phrases) {
- var start = phrase.position;
- var end = phrase.end;
- int numSamples = phrase.duration;
+ foreach(var note in selectedNotes) {
+ var start = note.position;
+ var end = note.position + note.duration;
+ int numSamples = note.duration;
float[] noiseSum = new float[numSamples];
Array.Fill(noiseSum, 0);