Skip to content

Instantly share code, notes, and snippets.

@TigerHix
Created August 3, 2018 15:27
Show Gist options
  • Save TigerHix/edf9933ce98da7ce92b9a70364ba4935 to your computer and use it in GitHub Desktop.
Save TigerHix/edf9933ce98da7ce92b9a70364ba4935 to your computer and use it in GitHub Desktop.
Converts a given Cytus chart to Cytus II formatted chart.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace TigerHix
{
class CytusChartConverter
{
public static void Fain(string[] args)
{
var chart = new Chart(File.ReadAllText(args[0]));
const int timeBase = 480;
var root = new JObject();
root["format_version"] = 0;
root["time_base"] = 480;
root["start_offset_time"] = 0;
var tempo = new JObject();
tempo["tick"] = 0;
var tempoValue = chart.PageDuration * 1000000;
tempo["value"] = tempoValue;
root["tempo_list"] = new JArray { tempo };
if (chart.PageShift < 0) chart.PageShift = chart.PageShift + 2 * chart.PageDuration;
var pageShiftTickOffset = chart.PageShift / chart.PageDuration * timeBase;
var noteList = new JArray();
var page = 0;
foreach (var note in chart.Notes.Values)
{
var obj = new JObject();
obj["id"] = note.Id;
switch (note.Type)
{
case Chart.NoteType.Single:
obj["type"] = 0;
break;
case Chart.NoteType.Chain:
obj["type"] = note.IsChainHead ? 3 : 4;
break;
case Chart.NoteType.Hold:
obj["type"] = 1;
break;
}
obj["x"] = note.X;
var ti = note.Time * timeBase * 1000000 / tempoValue + pageShiftTickOffset;
obj["tick"] = ti;
obj["hold_tick"] = note.Duration * timeBase * 1000000 / tempoValue;
page = (int) Math.Floor((double) ti / timeBase);
obj["page_index"] = page;
if (note.Type == Chart.NoteType.Chain)
{
obj["next_id"] = note.ConnectedNote != null ? note.ConnectedNote.Id : -1;
}
else
{
obj["next_id"] = 0;
}
noteList.Add(obj);
}
root["note_list"] = noteList;
var pageList = new JArray();
var direction = false;
var t = 0;
for (var i = 0; i <= page; i++)
{
var obj = new JObject();
obj["scan_line_direction"] = direction ? 1 : -1;
direction = !direction;
obj["start_tick"] = t;
t += timeBase;
obj["end_tick"] = t;
pageList.Add(obj);
}
root["page_list"] = pageList;
root["music_offset"] = pageShiftTickOffset / timeBase / 1000000 * tempoValue;
File.WriteAllText(Path.GetFileName(args[0]) + ".converted.txt", JsonConvert.SerializeObject(root));
}
}
public class Chart
{
public float PageDuration;
public float PageShift;
public Dictionary<int, Note> Notes = new Dictionary<int, Note>();
public List<int> ChronologicalIds;
public Chart(string text) {
var notes = new Dictionary<int, Note>();
foreach (var line in text.Split('\n'))
{
var data = line.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries);
if (data.Length == 0) continue;
var type = data[0];
switch (type)
{
case "PAGE_SIZE":
PageDuration = float.Parse(data[1]);
break;
case "PAGE_SHIFT":
PageShift = float.Parse(data[1]);
break;
case "NOTE":
var note = new Note(int.Parse(data[1]), float.Parse(data[2]), float.Parse(data[3]),
float.Parse(data[4]), false);
notes.Add(int.Parse(data[1]), note);
if (note.Duration > 0) note.Type = NoteType.Hold;
break;
case "LINK":
var notesInChain = new List<Note>();
for (var i = 1; i < data.Length; i++)
{
int id;
if (!int.TryParse(data[i], out id)) continue;
note = notes[id];
note.Type = NoteType.Chain;
notesInChain.Add(note);
}
for (var i = 0; i < notesInChain.Count - 1; i++)
{
notesInChain[i].ConnectedNote = notesInChain[i + 1];
}
notesInChain[0].IsChainHead = true;
break;
}
}
PageShift += PageDuration;
// Calculate chronological note ids
var noteList = notes.Values.ToList();
noteList.Sort((a, b) => a.Time.CompareTo(b.Time));
ChronologicalIds = noteList.Select(note => note.OriginalId).ToList();
// Recalculate note ids from original ids
var newId = 0;
foreach (var noteId in ChronologicalIds)
{
notes[noteId].Id = newId;
Notes[newId] = notes[noteId];
newId++;
}
// Reset chronological ids
ChronologicalIds.Clear();
for (var i = 0; i < notes.Count; i++)
{
ChronologicalIds.Add(i);
}
}
public class Note
{
public int Id;
public int OriginalId;
public float Time;
public float X;
public float Duration;
public NoteType Type = NoteType.Single;
public Note ConnectedNote;
public bool IsChainHead;
public Note(int originalId, float time, float x, float duration, bool isChainHead)
{
OriginalId = originalId;
Time = time;
X = x;
Duration = duration;
IsChainHead = isChainHead;
}
}
public enum NoteType
{
Single, Chain, Hold
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment