233 lines
10 KiB
C#
233 lines
10 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Xml.XPath;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
using JD.Asset.Template.Utils;
|
|
using JD.Collections.Extensions;
|
|
using JD.Serialization;
|
|
using JDSongConverter.Utils;
|
|
using TeaBox.Macros;
|
|
using FrameConverter = JD.Core.FrameConverter;
|
|
using JD.Timeline.Model;
|
|
|
|
namespace JDSongConverter.Tasks
|
|
{
|
|
/// <summary>
|
|
/// Converts different deprecated timeline files to karaoke tape file
|
|
/// </summary>
|
|
public class ConvertTimelineToKtapeTask : Task
|
|
{
|
|
public string TimelineFile { get; set; }
|
|
public string KaraokeTapeFile { get; set; }
|
|
public string LyricsFile { get; set; }
|
|
|
|
public void Init(string timelineFile, string karaokeTapeFile, string lyricsFile)
|
|
{
|
|
TimelineFile = timelineFile;
|
|
KaraokeTapeFile = karaokeTapeFile;
|
|
LyricsFile = lyricsFile;
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return "Convert timeline to karaoke tape"; }
|
|
set { }
|
|
}
|
|
|
|
public override string ProgressText
|
|
{
|
|
get { return "Converting timeline to karaoke tape"; }
|
|
}
|
|
|
|
public override TaskResult Process(IExecutionContext executionContext)
|
|
{
|
|
if (!File.Exists(TimelineFile))
|
|
return TaskResult.FileMissing;
|
|
|
|
var tape = new Tape();
|
|
|
|
if (TimelineFile.EndsWith(".tpl", StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
ImportTpl(tape, TimelineFile);
|
|
}
|
|
else if (TimelineFile.EndsWith(".tml", StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
ImportTml(tape, TimelineFile);
|
|
}
|
|
tape.Clips.OfType<KaraokeClip>().Where(x => x.ContentType == KaraokeClip.ContentType_Enum.KaraokeContent_LyricsOnly).FixCollisions();
|
|
|
|
tape.Save(KaraokeTapeFile);
|
|
|
|
UpdateLyricsFile(tape);
|
|
|
|
return TaskResult.Ok;
|
|
}
|
|
|
|
private void ImportTpl(Tape tape, string fileName)
|
|
{
|
|
var serializer = new LuaSerializer();
|
|
var actorTemplate = (Actor_Template)serializer.LoadObjectFromFile(fileName);
|
|
if (actorTemplate == null)
|
|
return;
|
|
|
|
JD_Timeline_Template timeline = actorTemplate.COMPONENTS.OfType<JD_Timeline_Template>().FirstOrDefault();
|
|
if (timeline == null)
|
|
return;
|
|
|
|
tape.Id = KaraokeTapeFile;
|
|
tape.IsLoading = true;
|
|
tape.TapeClock = Tape.TapeClock_Enum.TapeClock_ConductorGameplay;
|
|
tape.MapName = Context.Song.Name;
|
|
|
|
//We read karaoke scoring general parameters
|
|
var karaokeInfos = new KaraokeMetaInfo
|
|
{
|
|
Id = IdGenerator.Instance.Generate(),
|
|
HistorySpan = timeline.KaraokeScoringData.Params.HistorySpan,
|
|
NoPitchScoring = timeline.KaraokeScoringData.Params.NoPitchScoring,
|
|
PitchLowerBound = timeline.KaraokeScoringData.Params.PitchLowerBound,
|
|
PitchUpperBound = timeline.KaraokeScoringData.Params.PitchUpperBound,
|
|
RMSTendencyToDecrease = timeline.KaraokeScoringData.Params.RMSTendencyToDecrease,
|
|
RMSTendencyToIncrease = timeline.KaraokeScoringData.Params.RMSTendencyToIncrease,
|
|
RMSThreshold = timeline.KaraokeScoringData.Params.RMSThreshold,
|
|
SlidingMeanVariationThreshold = timeline.KaraokeScoringData.Params.SlidingMeanVariationThreshold,
|
|
SlidingMeanWindowSize = timeline.KaraokeScoringData.Params.SlidingMeanWindowSize,
|
|
WindowHop = timeline.KaraokeScoringData.Params.WindowHop,
|
|
WindowSize = timeline.KaraokeScoringData.Params.WindowSize,
|
|
YinPitchTreshold = timeline.KaraokeScoringData.Params.YINpitchThreshold,
|
|
};
|
|
tape.MetaInfos.Add(karaokeInfos);
|
|
|
|
//We read karaoke notes
|
|
foreach (var signalAnnotation in timeline.KaraokeScoringData.Vect)
|
|
{
|
|
var clip = new KaraokeClip
|
|
{
|
|
Id = IdGenerator.Instance.Generate(),
|
|
StartBeat = tape.TimeInBeats(signalAnnotation.StartTime),
|
|
BeatDuration = tape.TimeInBeats(signalAnnotation.EndTime) - tape.TimeInBeats(signalAnnotation.StartTime),
|
|
Pitch = signalAnnotation.Pitch,
|
|
ContentType = KaraokeClip.ContentType_Enum.KaraokeContent_Singing,
|
|
StartTimeTolerance = (int)FrameConverter.FrameFromTime(Math.Abs(tape.TimeInBeats(signalAnnotation.Tolerance.StartTime) - tape.TimeInBeats(signalAnnotation.StartTime))),
|
|
EndTimeTolerance = (int)FrameConverter.FrameFromTime(Math.Abs(tape.TimeInBeats(signalAnnotation.Tolerance.EndTime) - tape.TimeInBeats(signalAnnotation.EndTime))),
|
|
SemitoneTolerance = signalAnnotation.Tolerance.SemitoneTolerance,
|
|
TrackId = 0
|
|
};
|
|
tape.Clips.Add(clip);
|
|
}
|
|
|
|
//We read lyrics
|
|
foreach (var lyricsChunk in timeline.Lyrics)
|
|
{
|
|
var clip = new KaraokeClip
|
|
{
|
|
Id = IdGenerator.Instance.Generate(),
|
|
Lyrics = lyricsChunk.Text,
|
|
StartBeat = lyricsChunk.StartPosition,
|
|
BeatDuration = lyricsChunk.StopPosition - lyricsChunk.StartPosition,
|
|
ContentType = KaraokeClip.ContentType_Enum.KaraokeContent_LyricsOnly,
|
|
IsEndOfLine = (lyricsChunk.IsLineEnding > 0),
|
|
MidiNote = 0,
|
|
TrackId = 0
|
|
};
|
|
tape.Clips.Add(clip);
|
|
}
|
|
|
|
}
|
|
|
|
private void ImportTml(Tape tape, string fileName)
|
|
{
|
|
tape.Id = KaraokeTapeFile;
|
|
tape.IsLoading = true;
|
|
tape.TapeClock = Tape.TapeClock_Enum.TapeClock_ConductorGameplay;
|
|
tape.MapName = Context.Song.Name;
|
|
|
|
XDocument xmlFile = XDocument.Load(fileName);
|
|
var layers = xmlFile.XPathSelectElements("/JustDanceToolLD/partition/layer").ToList();
|
|
|
|
//We read lyrics
|
|
var layerNamedLyrics = layers.FirstOrDefault(x => x.Attribute("name").Value == "Lyrics");
|
|
var lyricsClips = new UAFList<KaraokeClip>();
|
|
if (layerNamedLyrics != null)
|
|
{
|
|
foreach (var instance in layerNamedLyrics.Descendants("instance"))
|
|
{
|
|
int position = Int32.Parse(instance.Attribute("position").Value)-1;
|
|
var offset = (float)XmlUtils.ReadDoubleValue(instance.Element("Offset"), 0);
|
|
var length = (float)XmlUtils.ReadDoubleValue(instance.Element("Length"), 0);
|
|
var lyrics = XmlUtils.ReadStringValue(instance.Element("Text"), "");
|
|
var clip = new KaraokeClip
|
|
{
|
|
Id = IdGenerator.Instance.Generate(),
|
|
StartBeat = tape.TimeInBeats(position, offset),
|
|
BeatDuration = tape.TimeInBeats(position, offset + length) - tape.TimeInBeats(position, offset),
|
|
ContentType = KaraokeClip.ContentType_Enum.KaraokeContent_LyricsOnly,
|
|
MidiNote = 0,
|
|
TrackId = 0,
|
|
IsEndOfLine = true,
|
|
Lyrics = lyrics.Replace("_", " ")
|
|
};
|
|
lyricsClips.Add(clip);
|
|
}
|
|
}
|
|
|
|
|
|
var layerNamedKaraoke = layers.FirstOrDefault(x => x.Attribute("name").Value == "Karaoke");
|
|
var layerNamedLyricsKaraoke = layers.FirstOrDefault(x => x.Attribute("name").Value == "LyricsKaraoke");
|
|
var karaokeLayer = layerNamedLyricsKaraoke ?? layerNamedKaraoke;
|
|
if (karaokeLayer != null)
|
|
{
|
|
foreach (var instance in karaokeLayer.Descendants("instance"))
|
|
{
|
|
var previousClip = tape.Clips.LastOrDefault();
|
|
|
|
int position = Int32.Parse(instance.Attribute("position").Value)-1;
|
|
var offset = (float)XmlUtils.ReadDoubleValue(instance.Element("Offset"), 0);
|
|
var length = (float)XmlUtils.ReadDoubleValue(instance.Element("Length"), 0);
|
|
var lyrics = XmlUtils.ReadStringValue(instance.Element("Text"), "");
|
|
var clip = new KaraokeClip
|
|
{
|
|
Id = IdGenerator.Instance.Generate(),
|
|
StartBeat = tape.TimeInBeats(position,offset),
|
|
BeatDuration = tape.TimeInBeats(position, offset + length) - tape.TimeInBeats(position, offset),
|
|
ContentType = KaraokeClip.ContentType_Enum.KaraokeContent_LyricsOnly,
|
|
MidiNote = 0,
|
|
TrackId = 0,
|
|
Lyrics = lyrics.Replace("_", " ")
|
|
};
|
|
|
|
var currentLyricsLine = lyricsClips.FirstOrDefault(x => x.StartBeat <= clip.StartBeat && x.StopBeat >= clip.StopBeat);
|
|
clip.IsEndOfLine = currentLyricsLine != null && currentLyricsLine.Lyrics.EndsWith(clip.Lyrics, StringComparison.OrdinalIgnoreCase);
|
|
|
|
tape.Clips.Add(clip);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tape.Clips.AddRange(lyricsClips);
|
|
}
|
|
}
|
|
|
|
private void UpdateLyricsFile(Tape tape)
|
|
{
|
|
if (!System.IO.File.Exists(LyricsFile) || System.IO.File.ReadAllText(LyricsFile).StartsWith("Lorem ipsum") || string.IsNullOrEmpty(System.IO.File.ReadAllText(LyricsFile)))
|
|
{
|
|
string lyrics = "";
|
|
foreach (var karaokeClip in tape.Clips.OfType<KaraokeClip>())
|
|
{
|
|
lyrics += karaokeClip.Lyrics;
|
|
if (karaokeClip.IsEndOfLine)
|
|
{
|
|
lyrics += Environment.NewLine;
|
|
}
|
|
}
|
|
if (File.Exists(LyricsFile))
|
|
{
|
|
File.SetAttributes(LyricsFile, FileAttributes.Normal);
|
|
}
|
|
System.IO.File.WriteAllText(LyricsFile, lyrics);
|
|
}
|
|
}
|
|
}
|
|
}
|