Пример #1
0
        public void SetExpression(UProject project, string abbr, float value)
        {
            var descriptor = project.expressions[abbr];
            var note       = Parent.Extends ?? Parent;
            int index      = Parent.PhonemeOffset + Index;

            if (descriptor.defaultValue == value)
            {
                note.phonemeExpressions.RemoveAll(exp => exp.descriptor == descriptor && exp.index == index);
                return;
            }
            var expression = note.phonemeExpressions.FirstOrDefault(exp => exp.descriptor == descriptor && exp.index == index);

            if (expression != null)
            {
                expression.value = value;
            }
            else
            {
                note.phonemeExpressions.Add(new UExpression(descriptor)
                {
                    descriptor = descriptor,
                    index      = index,
                    value      = value,
                });
            }
        }
Пример #2
0
 public override void BeforeSave(UProject project, UTrack track)
 {
     foreach (var note in notes)
     {
         note.BeforeSave(project, track, this);
     }
 }
Пример #3
0
        public string GetResamplerFlags(UProject project)
        {
            StringBuilder builder = new StringBuilder();

            foreach (var descriptor in project.expressions.Values)
            {
                if (descriptor.type == UExpressionType.Numerical)
                {
                    if (!string.IsNullOrEmpty(descriptor.flag))
                    {
                        builder.Append(descriptor.flag);
                        int value = (int)GetExpression(project, descriptor.abbr).Item1;
                        builder.Append(value);
                    }
                }
                if (descriptor.type == UExpressionType.Options)
                {
                    if (descriptor.isFlag)
                    {
                        int value = (int)GetExpression(project, descriptor.abbr).Item1;
                        builder.Append(descriptor.options[value]);
                    }
                }
            }
            return(builder.ToString());
        }
Пример #4
0
 public override void AfterLoad(UProject project, UTrack track)
 {
     foreach (var note in notes)
     {
         note.AfterLoad(project, track, this);
     }
     Duration = GetBarDurTick(project);
 }
Пример #5
0
 public void Validate(UProject project, UTrack track, UVoicePart part, UNote note)
 {
     Error = note.Error;
     ValidateDuration(note);
     ValidateOto(track, note);
     ValidateOverlap(project, note);
     ValidateEnvelope(project, note);
 }
Пример #6
0
 public void BeforeSave(UProject project, UTrack track, UVoicePart part)
 {
     noteExpressions.ForEach(exp => exp.index = null);
     noteExpressions = noteExpressions
                       .OrderBy(exp => exp.abbr)
                       .ToList();
     phonemeExpressions = phonemeExpressions
                          .OrderBy(exp => exp.index)
                          .ThenBy(exp => exp.abbr)
                          .ToList();
 }
Пример #7
0
 public void AfterLoad(UProject project, UTrack track, UVoicePart part)
 {
     foreach (var exp in noteExpressions)
     {
         exp.descriptor = project.expressions[exp.abbr];
     }
     foreach (var exp in phonemeExpressions)
     {
         exp.descriptor = project.expressions[exp.abbr];
     }
 }
Пример #8
0
        public override void Validate(UProject project, UTrack track)
        {
            UNote lastNote = null;

            foreach (UNote note in notes)
            {
                note.Prev = lastNote;
                note.Next = null;
                if (lastNote != null)
                {
                    lastNote.Next = note;
                }
                lastNote = note;
            }
            foreach (UNote note in notes)
            {
                note.ExtendedDuration = note.duration;
                if (note.Prev != null && note.Prev.End == note.position && note.lyric.StartsWith("..."))
                {
                    note.Extends = note.Prev.Extends ?? note.Prev;
                    note.Extends.ExtendedDuration = note.End - note.Extends.position;
                }
                else
                {
                    note.Extends = null;
                }
            }
            foreach (UNote note in notes.Reverse())
            {
                note.Phonemize(project, track);
            }
            UPhoneme lastPhoneme = null;

            foreach (UNote note in notes)
            {
                foreach (var phoneme in note.phonemes)
                {
                    phoneme.Parent = note;
                    phoneme.Prev   = lastPhoneme;
                    phoneme.Next   = null;
                    if (lastPhoneme != null)
                    {
                        lastPhoneme.Next = phoneme;
                    }
                    lastPhoneme = phoneme;
                }
            }
            foreach (UNote note in notes)
            {
                note.Validate(project, track, this);
            }
        }
Пример #9
0
        public Tuple <float, bool> GetExpression(UProject project, string abbr)
        {
            var descriptor = project.expressions[abbr];
            var note       = Parent.Extends ?? Parent;
            int index      = Parent.PhonemeOffset + Index;
            var expression = note.phonemeExpressions.FirstOrDefault(exp => exp.descriptor == descriptor && exp.index == index);

            if (expression != null)
            {
                return(Tuple.Create(expression.value, true));
            }
            else
            {
                return(Tuple.Create(descriptor.defaultValue, false));
            }
        }
Пример #10
0
        void ValidateOverlap(UProject project, UNote note)
        {
            if (Error)
            {
                return;
            }
            float consonantStretch = (float)Math.Pow(2f, 1.0f - GetExpression(project, "vel").Item1 / 100f);

            overlap    = (float)oto.Overlap * consonantStretch * (overlapScale ?? 1);
            preutter   = (float)oto.Preutter * consonantStretch * (preutterScale ?? 1);
            overlapped = false;

            if (Prev == null)
            {
                return;
            }
            int   gapTick     = Parent.position + position - (Prev.Parent.position + Prev.End);
            float gapMs       = (float)project.TickToMillisecond(gapTick);
            float maxPreutter = preutter;

            if (gapMs <= 0)
            {
                // Keep at least half of last phoneme, or 10% if preutterScale is set.
                overlapped  = true;
                maxPreutter = (float)project.TickToMillisecond(Prev.Duration) * (preutterScale == null ? 0.5f : 0.9f);
            }
            else if (gapMs < preutter)
            {
                maxPreutter = gapMs;
            }
            if (preutter > maxPreutter)
            {
                float ratio = maxPreutter / preutter;
                preutter = maxPreutter;
                overlap *= ratio;
            }
            preutter         = Math.Max(0, preutter);
            overlap          = Math.Min(overlap, preutter);
            Prev.tailIntrude = overlapped ? preutter : 0;
            Prev.tailOverlap = overlapped ? overlap : 0;
            Prev.ValidateEnvelope(project, Prev.Parent);
            if (Next == null)
            {
                tailIntrude = 0;
                tailOverlap = 0;
            }
        }
Пример #11
0
        void ValidateEnvelope(UProject project, UNote note)
        {
            if (Error)
            {
                return;
            }
            var vol = GetExpression(project, "vol").Item1;
            var atk = GetExpression(project, "atk").Item1;
            var dec = GetExpression(project, "dec").Item1;

            Vector2 p0, p1, p2, p3, p4;

            p0.X = -preutter;
            p1.X = p0.X + (overlapped ? overlap : 5f);
            p2.X = Math.Max(0f, p1.X);
            p3.X = (float)project.TickToMillisecond(Duration) - (float)tailIntrude;
            p4.X = p3.X + (float)tailOverlap;
            if (p3.X == p4.X)
            {
                p3.X = Math.Max(p2.X, p3.X - 25f);
            }

            p0.Y = 0f;
            p1.Y = vol;
            p1.X = p0.X + (overlapped ? overlap : 5f);
            p1.Y = atk * vol / 100f;
            p2.Y = vol;
            p3.Y = vol * (1f - dec / 100f);
            p4.Y = 0f;

            envelope.data[0] = p0;
            envelope.data[1] = p1;
            envelope.data[2] = p2;
            envelope.data[3] = p3;
            envelope.data[4] = p4;
        }
Пример #12
0
 public abstract int GetMinDurTick(UProject project);
Пример #13
0
 public virtual void AfterLoad(UProject project, UTrack track)
 {
 }
Пример #14
0
 public virtual void Validate(UProject project, UTrack track)
 {
 }
Пример #15
0
        public void Phonemize(UProject project, UTrack track)
        {
            if (track.Singer == null || !track.Singer.Loaded)
            {
                return;
            }
            if (Extends != null)
            {
                return;
            }

            List <UNote> notes = new List <UNote> {
                this
            };

            while (notes.Last().Next != null && notes.Last().Next.Extends == this)
            {
                notes.Add(notes.Last().Next);
            }

            int endOffset = 0;

            if (notes.Last().Next != null && notes.Last().Next.phonemes.Count > 0)
            {
                endOffset = Math.Min(0, notes.Last().Next.position - notes.Last().End + notes.Last().Next.phonemes[0].position);
            }

            var  prev            = Prev?.ToProcessorNote();
            var  next            = notes.Last().Next?.ToProcessorNote();
            bool prevIsNeighbour = Prev?.End >= position;

            if (Prev?.Extends != null)
            {
                prev = Prev.Extends.ToProcessorNote();
                var phoneme = prev.Value;
                phoneme.duration = Prev.ExtendedDuration;
                prev             = phoneme;
            }
            bool nextIsNeighbour = notes.Last().End >= notes.Last().Next?.position;

            track.Phonemizer.SetTiming(project.bpm, project.beatUnit, project.resolution);
            var phonemizerNotes = notes.Select(note => note.ToProcessorNote()).ToArray();

            phonemizerNotes[phonemizerNotes.Length - 1].duration += endOffset;
            if (string.IsNullOrEmpty(phonemizerNotes[0].lyric) &&
                string.IsNullOrEmpty(phonemizerNotes[0].phoneticHint))
            {
                phonemes.Clear();
                return;
            }
            Phonemizer.Result phonemizerResult;
            try {
                phonemizerResult = track.Phonemizer.Process(
                    phonemizerNotes,
                    prev,
                    next,
                    prevIsNeighbour ? prev : null,
                    nextIsNeighbour ? next : null);
            } catch (Exception e) {
                Log.Error(e, "phonemizer error");
                phonemizerResult = new Phonemizer.Result()
                {
                    phonemes = new Phonemizer.Phoneme[] {
                        new Phonemizer.Phoneme {
                            phoneme = "error"
                        }
                    }
                };
            }
            var newPhonemes = phonemizerResult.phonemes;

            // Apply overrides.
            for (int i = phonemeOverrides.Count - 1; i >= 0; --i)
            {
                if (phonemeOverrides[i].IsEmpty)
                {
                    phonemeOverrides.RemoveAt(i);
                }
            }
            foreach (var o in phonemeOverrides)
            {
                if (o.index >= 0 && o.index < newPhonemes.Length)
                {
                    var p = newPhonemes[o.index];
                    if (o.phoneme != null)
                    {
                        p.phoneme = o.phoneme;
                    }
                    if (o.offset != null)
                    {
                        p.position += o.offset.Value;
                    }
                    newPhonemes[o.index] = p;
                }
            }
            // Safety treatment after phonemizer output and phoneme overrides.
            int maxPostion = notes.Last().End - notes.First().position + endOffset - 10;

            for (int i = newPhonemes.Length - 1; i >= 0; --i)
            {
                var p = newPhonemes[i];
                p.position     = Math.Min(p.position, maxPostion);
                newPhonemes[i] = p;
                maxPostion     = p.position - 10;
            }
            DistributePhonemes(notes, newPhonemes);
        }
Пример #16
0
 public void Validate(UProject project, UTrack track, UVoicePart part)
 {
     duration = Math.Max(10, duration);
     if (Prev != null && Prev.End > position)
     {
         Error        = true;
         OverlapError = true;
         return;
     }
     Error        = false;
     OverlapError = false;
     if (track.Singer == null || !track.Singer.Loaded)
     {
         Error |= true;
     }
     if (pitch.snapFirst)
     {
         if (Prev != null && Prev.End == position)
         {
             pitch.data[0].Y = (Prev.tone - tone) * 10;
         }
         else
         {
             pitch.data[0].Y = 0;
         }
     }
     for (var i = 0; i < phonemes.Count; i++)
     {
         var phoneme = phonemes[i];
         phoneme.Parent = this;
         phoneme.Index  = i;
     }
     foreach (var phoneme in phonemes)
     {
         phoneme.Validate(project, track, part, this);
         Error |= phoneme.Error;
     }
     // Update has override bits.
     foreach (var phoneme in phonemes)
     {
         phoneme.HasPhonemeOverride = false;
         phoneme.HasOffsetOverride  = false;
         phoneme.preutterScale      = null;
         phoneme.overlapScale       = null;
     }
     foreach (var o in (Extends ?? this).phonemeOverrides)
     {
         int index = o.index - PhonemeOffset;
         if (index >= 0 && index < phonemes.Count)
         {
             if (o.phoneme != null)
             {
                 phonemes[index].HasPhonemeOverride = true;
             }
             if (o.offset != null)
             {
                 phonemes[index].HasOffsetOverride = true;
             }
             phonemes[index].preutterScale = o.preutterScale;
             phonemes[index].overlapScale  = o.overlapScale;
         }
     }
 }
Пример #17
0
 public virtual void BeforeSave(UProject project, UTrack track)
 {
 }
Пример #18
0
 public override int GetMinDurTick(UProject project)
 {
     return(notes.Count > 0
         ? Math.Max(project.BarTicks, notes.Last().End)
         : project.BarTicks);
 }
Пример #19
0
        public int GetBarDurTick(UProject project)
        {
            int barTicks = project.BarTicks;

            return((int)Math.Ceiling((double)GetMinDurTick(project) / barTicks) * barTicks);
        }