public static void Normalize(List <Smi> smis) { int startIndex = -1; for (int i = 1; i < smis.Count; i++) { if (smis[i].syncType == SyncType.inner) { if (startIndex < 0) { startIndex = i - 1; } } else { if (startIndex >= 0) { int endIndex = i; if (smis[startIndex].syncType == smis[endIndex].syncType) { int startSync = smis[startIndex].start; int endSync = smis[endIndex].start; int count = endIndex - startIndex; for (int j = 1; j < count; j++) { smis[startIndex + j].start = ((count - j) * startSync + j * endSync) / count; } } startIndex = -1; } } } for (int i = 0; i < smis.Count - 1; i++) { Smi smi = smis[i]; if (smi.syncType != smis[i + 1].syncType) { // 전후 싱크 타입이 맞을 때만 안전함 continue; } string lower = smi.text.ToLower(); if (lower.IndexOf(" fade=") > 0) { List <Color> fadeColors = new List <Color>(); List <Attr> attrs = smi.ToAttr(); for (int j = 0; j < attrs.Count; j++) { if (attrs[j].fade != 0) { string color = (attrs[j].fc.Length == 6) ? attrs[j].fc : "ffffff"; fadeColors.Add(new Color(j, attrs[j].fade > 0, color)); attrs[j].fade = 0; } } if (fadeColors.Count == 0) { continue; } int start = smi.start, end = smis[i + 1].start; int frames = (int)Math.Round((end - start) * 24 / 1001.0); foreach (Color color in fadeColors) { Attr attr = attrs[color.index]; if (color.isIn) { attr.fc = color.Get(1, 2 * frames); } else { attr.fc = color.Get(2 * frames - 1, 2 * frames); } } smi.FromAttr(attrs); for (int j = 1; j < frames; j++) { foreach (Color color in fadeColors) { Attr attr = attrs[color.index]; if (color.isIn) { attr.fc = color.Get(1 + 2 * j, 2 * frames); } else { attr.fc = color.Get(2 * frames - (1 + 2 * j), 2 * frames); } } smis.Insert(i + j, new Smi() { start = (start * (frames - j) + end * j) / frames, //syncType = 2, syncType = SyncType.inner }.FromAttr(attrs)); } i += frames - 1; } else if (lower.IndexOf(" typing=") > 0) { // 타이핑은 한 싱크에 하나만 가능 int attrIndex = -1; Attr attr = null; List <Attr> attrs = smi.ToAttr(); bool isLastAttr = false; for (int j = 0; j < attrs.Count; j++) { if (attrs[j].typing != null) { string color = (attrs[j].fc.Length == 6) ? attrs[j].fc : "ffffff"; attr = attrs[(attrIndex = j)]; string remains = ""; for (int k = j + 1; k < attrs.Count; k++) { remains += attrs[k].text; } isLastAttr = remains.Length == 0 || remains.StartsWith("\n"); if (!isLastAttr) { int length = 0; for (int k = j + 1; k < attrs.Count; k++) { length += attrs[k].text.Length; } isLastAttr = (length == 0); } break; } } if (attr == null) { continue; } List <string> types = Typing.ToType(attr.text, attr.typing.mode, attr.typing.cursor); float width = GetLineWidth(attr.text); int start = smi.start, end = smis[i + 1].start; int count = types.Count - attr.typing.end - attr.typing.start; if (count < 1) { continue; } int typingStart = attr.typing.start; attr.typing = null; smis.RemoveAt(i); for (int j = 0; j < count; j++) { string text = types[j + typingStart]; attr.text = Width.GetAppend(GetLineWidth(text), width) + (isLastAttr ? "" : ""); List <Attr> tAttrs = new List <Attr>(); tAttrs.AddRange(attrs.GetRange(0, attrIndex)); tAttrs.AddRange(new Smi() { text = text }.ToAttr()); tAttrs.Add(attr); if (!isLastAttr) { tAttrs.AddRange(attrs.GetRange(attrIndex + 1, attrs.Count - attrIndex - 1)); } smis.Insert(i + j, new Smi() { start = (start * (count - j) + end * (j)) / count, syncType = j == 0 ? smi.syncType : SyncType.inner }.FromAttr(tAttrs)); } i += count - 1; } } }