public override ChartFormat DecodeChart(FormatData data, ProgressIndicator progress) { if (!data.HasStream(this, ChartName) || !data.HasStream(this, SectionsName)) { throw new FormatException(); } progress.NewTask(6 + 8); Stream chartstream = data.GetStream(this, ChartName); Stream sectionstream = data.GetStream(this, SectionsName); PakFormat format = NeversoftMetadata.GetSongItemType(data.Song); SongData song = NeversoftMetadata.GetSongData(data.PlatformData, NeversoftMetadata.GetSongItem(data)); Pak chartpak = new Pak(new EndianReader(chartstream, Endianness.BigEndian)); // TODO: Endianness based on format? FileNode chartfile = chartpak.Root.Find(song.ID + ".mid.qb.ngc", SearchOption.AllDirectories, true) as FileNode; QbFile qbsections = new QbFile(sectionstream, format); QbFile qbchart = new QbFile(chartfile.Data, format); NoteChart chart = new NoteChart(); chart.PartGuitar = new NoteChart.Guitar(chart); chart.PartBass = new NoteChart.Bass(chart); chart.Events = new NoteChart.EventsTrack(chart); chart.Venue = new NoteChart.VenueTrack(chart); chart.Beat = new NoteChart.BeatTrack(chart); progress.Progress(); DecodeChartFretbars(song, qbchart, chart); progress.Progress(); DecodeChartMarkers(song, qbsections, qbchart, chart); progress.Progress(); for (NoteChart.TrackType track = NoteChart.TrackType.Guitar; track <= NoteChart.TrackType.Bass; track++) { for (NoteChart.Difficulty difficulty = NoteChart.Difficulty.Easy; difficulty <= NoteChart.Difficulty.Expert; difficulty++) { DecodeChartNotes(data, song, qbchart, chart, track, difficulty, data.Song.Data.GetValue <bool>("GH3ChartCoop")); progress.Progress(); } } progress.Progress(); DecodeChartDrums(song, qbchart, chart); progress.Progress(); DecodeChartVenue(song, qbchart, chart); ImportMap.ImportChart(data.Song, chart); progress.Progress(); data.CloseStream(chartstream); data.CloseStream(sectionstream); progress.EndTask(); return(new ChartFormat(chart)); }
public override FormatData CreateSong(PlatformData data, SongData song) { return(new TemporaryFormatData(song, data)); }
public bool PopulateChart(SongData song, NoteChart chart) { if (Root == null) { return(false); } string idprefix = string.Empty; bool ret = false; foreach (XmlElement node in Root.GetElementsByTagName("global")) { foreach (XmlElement element in node.GetElementsByTagName("idprefix")) { idprefix = element.InnerText; } } string songid = song.ID; if (songid.StartsWith(idprefix)) { songid = songid.Substring(idprefix.Length); } List <SoloInfo> solos = new List <SoloInfo>(); foreach (XmlElement element in Root.GetElementsByTagName("song")) { if (element.Attributes["game"] != null && int.Parse(element.Attributes["game"].Value) != (int)Game) { continue; } if (string.Compare(element.Attributes["id"].Value, songid, true) == 0) { foreach (XmlElement soloelement in element.GetElementsByTagName("solo")) { string startsection = soloelement.Attributes["start"] != null ? soloelement.Attributes["start"].Value : string.Empty; string endsection = soloelement.Attributes["end"] != null ? soloelement.Attributes["end"].Value : startsection; float startoffset = float.Parse(soloelement.Attributes["startoffset"] != null ? soloelement.Attributes["startoffset"].Value : "0"); float endoffset = float.Parse(soloelement.Attributes["endoffset"] != null ? soloelement.Attributes["endoffset"].Value : "0"); Instrument instrument = soloelement.Attributes["instrument"] != null?Platform.InstrumentFromString(soloelement.Attributes["instrument"].Value) : Instrument.Guitar; if (!startsection.HasValue()) { continue; } NoteChart.Point start = new NoteChart.Point(chart.Events.Sections.Find(e => string.Compare(e.Value, startsection, true) == 0).Key.Time); int endindex = chart.Events.Sections.FindIndex(e => string.Compare(e.Value, endsection, true) == 0); NoteChart.Point end; if (endindex + 1 < chart.Events.Sections.Count) { end = new NoteChart.Point(chart.Events.Sections[endindex + 1].Key.Time); } else { end = new NoteChart.Point(chart.Events.End.Time); } start.Time += (ulong)(startoffset * (float)chart.Division.TicksPerBeat); end.Time += (ulong)(endoffset * (float)chart.Division.TicksPerBeat); NoteChart.Note note = new NoteChart.Note(start.Time, end.Time - start.Time); if (instrument == Instrument.Guitar) { chart.PartGuitar.SoloSections.Add(note); } else if (instrument == Instrument.Bass) { chart.PartBass.SoloSections.Add(note); } else if (instrument == Instrument.Drums) { chart.PartDrums.SoloSections.Add(note); } ret = true; } } } return(ret); }
private static void DecodeChartNotes(FormatData data, SongData song, QbFile qbchart, NoteChart chart, NoteChart.TrackType track, NoteChart.Difficulty difficulty, bool coop) { string basetrack = string.Empty; string basetrackstar = string.Empty; string basetrackstarbattle = string.Empty; string basetrackfaceoff = string.Empty; NoteChart.Instrument instrument = null; switch (track) { case NoteChart.TrackType.Guitar: basetrack = song.ID + (coop ? "_song_guitarcoop_" : "_song_") + difficulty.DifficultyToString(); basetrackstar = song.ID + (coop ? "_guitarcoop_" : "_") + difficulty.DifficultyToString() + "_Star"; basetrackstarbattle = song.ID + (coop ? "_guitarcoop_" : "_") + difficulty.DifficultyToString() + "_StarBattleMode"; basetrackfaceoff = song.ID + "_FaceOffp"; instrument = chart.PartGuitar; break; case NoteChart.TrackType.Bass: basetrack = song.ID + (coop ? "_song_rhythmcoop_" : "_song_rhythm_") + difficulty.DifficultyToString(); basetrackstar = song.ID + (coop ? "_rhythmcoop_" : "_rhythm_") + difficulty.DifficultyToString() + "_Star"; basetrackstarbattle = song.ID + (coop ? "_rhythmcoop_" : "_rhythm_") + difficulty.DifficultyToString() + "_StarBattleMode"; basetrackfaceoff = song.ID + "_FaceOffP"; instrument = chart.PartBass; break; } if (instrument == null) { return; } if (difficulty == NoteChart.Difficulty.Expert) // GH3 has SP for each difficulty; RB2 has one OD for all { QbItemArray faceoff1 = (qbchart.FindItem(QbKey.Create(basetrackfaceoff + "1"), false) as QbItemArray).Items[0] as QbItemArray; if (faceoff1 != null) { foreach (QbItemInteger faceoff in faceoff1.Items) { NoteChart.Note fnote = new NoteChart.Note(chart.GetTicks(faceoff.Values[0]), chart.GetTicksDuration(faceoff.Values[0], faceoff.Values[1])); instrument.Player1.Add(fnote); } } QbItemArray faceoff2 = (qbchart.FindItem(QbKey.Create(basetrackfaceoff + "2"), false) as QbItemArray).Items[0] as QbItemArray; if (faceoff2 != null) { foreach (QbItemInteger faceoff in faceoff2.Items) { NoteChart.Note fnote = new NoteChart.Note(chart.GetTicks(faceoff.Values[0]), chart.GetTicksDuration(faceoff.Values[0], faceoff.Values[1])); instrument.Player2.Add(fnote); } } QbItemArray starpower = (qbchart.FindItem(QbKey.Create(basetrackstar), false) as QbItemArray).Items[0] as QbItemArray; if (starpower != null) { foreach (QbItemInteger star in starpower.Items) { instrument.Overdrive.Add(new NoteChart.Note(chart.GetTicks(star.Values[0]), chart.GetTicksDuration(star.Values[0], star.Values[1]))); } } if (instrument.Overdrive.Count == 0) { starpower = (qbchart.FindItem(QbKey.Create(basetrackstarbattle), false) as QbItemArray).Items[0] as QbItemArray; if (starpower != null) { foreach (QbItemInteger star in starpower.Items) { instrument.Overdrive.Add(new NoteChart.Note(chart.GetTicks(star.Values[0]), chart.GetTicksDuration(star.Values[0], star.Values[1]))); } } } } int previouschordnum = 0; int previouschord = 0; NoteChart.Note previousnote = new NoteChart.Note() { Time = uint.MaxValue, Duration = 0 }; QbItemInteger notes = (qbchart.FindItem(QbKey.Create(basetrack), false) as QbItemArray).Items[0] as QbItemInteger; if (notes == null) { if (track == NoteChart.TrackType.Guitar) { chart.PartGuitar = null; } else { chart.PartBass = null; } return; } int note32 = chart.Division.TicksPerBeat / 8; int note16 = chart.Division.TicksPerBeat / 4; for (int k = 0; k < notes.Values.Length; k += 3) { NoteChart.Note note = new NoteChart.Note(chart.GetTicks(notes.Values[k]), chart.GetTicksDuration(notes.Values[k], notes.Values[k + 1])); int chordnum = 0; int chord = 0; // Cut off sustains to a 32nd note before the next previousnote.Duration = (ulong)Math.Max(Math.Min((long)previousnote.Duration, (long)note.Time - (long)previousnote.Time - note16), note32); bool hopo = note.Time - previousnote.Time <= (ulong)data.Song.HopoThreshold; bool ishopo = hopo; hopo = hopo && previouschordnum == 1; uint fret = notes.Values[k + 2]; for (int l = 0; l < 6; l++) { if ((fret & 0x01) != 0) { if (l < 5) { chord = l; chordnum++; (instrument as NoteChart.IGems).Gems[difficulty][l].Add(note); } else // l == 5; hopo toggle bit { ishopo = !ishopo; } } fret >>= 1; } if (chordnum == 0) // Old TheGHOST bug, should be a green note { chordnum = 1; chord = 0; (instrument as NoteChart.IGems).Gems[difficulty][0].Add(note); } if (chord == previouschord) { ishopo = false; } if (ishopo != hopo && chordnum == 1) { if (ishopo) { (instrument as NoteChart.IForcedHopo).ForceHammeron[difficulty].Add(note); } else { (instrument as NoteChart.IForcedHopo).ForceStrum[difficulty].Add(note); } } previouschord = chord; previousnote = note; previouschordnum = chordnum; } }
private void DecodeChartNotes(SongData song, QbFile qbchart, Notes notes, NoteChart chart, NoteChart.TrackType track, NoteChart.Difficulty difficulty) { bool expertplus = song.Data.GetValue <bool>("GH5ChartExpertPlus"); uint[] values; uint[][] jaggedvalues; QbKey basetrack = null; QbKey basetrackstar = null; QbKey basetrackfaceoff1 = null; QbKey basetrackfaceoff2 = null; QbKey basetracktapping = null; NoteChart.Instrument instrument = null; switch (track) { case NoteChart.TrackType.Guitar: instrument = chart.PartGuitar; if (notes != null) { basetrack = QbKey.Create("guitar" + difficulty.DifficultyToString().ToLower() + "instrument"); basetracktapping = QbKey.Create("guitar" + difficulty.DifficultyToString().ToLower() + "tapping"); basetrackstar = QbKey.Create("guitar" + difficulty.DifficultyToString().ToLower() + "starpower"); } else { basetrack = QbKey.Create(song.ID + "_song_" + difficulty.DifficultyToString().ToLower()); basetrackstar = QbKey.Create(song.ID + "_" + difficulty.DifficultyToString().ToLower() + "_star"); basetrackfaceoff1 = QbKey.Create(song.ID + "_faceoffp1"); basetrackfaceoff2 = QbKey.Create(song.ID + "_faceoffp2"); basetracktapping = QbKey.Create(song.ID + "_" + difficulty.DifficultyToString().ToLower() + "_tapping"); } break; case NoteChart.TrackType.Bass: instrument = chart.PartBass; if (notes != null) { basetrack = QbKey.Create("bass" + difficulty.DifficultyToString().ToLower() + "instrument"); basetracktapping = QbKey.Create("bass" + difficulty.DifficultyToString().ToLower() + "tapping"); basetrackstar = QbKey.Create("bass" + difficulty.DifficultyToString().ToLower() + "starpower"); } else { basetrack = QbKey.Create(song.ID + "_song_rhythm_" + difficulty.DifficultyToString().ToLower()); basetrackstar = QbKey.Create(song.ID + "_rhythm_" + difficulty.DifficultyToString().ToLower() + "_star"); basetrackfaceoff1 = QbKey.Create(song.ID + "_rhythm_faceoffp1"); basetrackfaceoff2 = QbKey.Create(song.ID + "_rhythm_faceoffp2"); // basetracktapping = song.ID + "_rhythm_" + difficulty.DifficultyToString().ToLower() + "_tapping"; } break; case NoteChart.TrackType.Drums: instrument = chart.PartDrums; if (notes != null) { basetrack = QbKey.Create("drums" + difficulty.DifficultyToString().ToLower() + "instrument"); basetrackstar = QbKey.Create("drums" + difficulty.DifficultyToString().ToLower() + "starpower"); } else { basetrack = QbKey.Create(song.ID + "_song_drum_" + difficulty.DifficultyToString().ToLower()); basetrackstar = QbKey.Create(song.ID + "_drum_" + difficulty.DifficultyToString().ToLower() + "_star"); basetrackfaceoff1 = QbKey.Create(song.ID + "_drum_faceoffp1"); basetrackfaceoff2 = QbKey.Create(song.ID + "_drum_faceoffp2"); // basetracktapping = song.ID + "_drum_" + difficulty.DifficultyToString().ToLower() + "_tapping"; } break; } if (difficulty == NoteChart.Difficulty.Expert) // GH has SP for each difficulty; RB2 has one OD for all { jaggedvalues = GetJaggedChartValues(notes, qbchart, basetrackstar, basetrackstar, 4, 2); foreach (uint[] star in jaggedvalues) { instrument.Overdrive.Add(new NoteChart.Note(chart.GetTicks(star[0]), chart.GetTicksDuration(star[0], star[1]))); } if (notes == null) { jaggedvalues = GetJaggedChartValues(notes, qbchart, basetrackfaceoff1, basetrackfaceoff1, 1); foreach (uint[] faceoff in jaggedvalues) { instrument.Player1.Add(new NoteChart.Note(chart.GetTicks(faceoff[0]), chart.GetTicksDuration(faceoff[0], faceoff[1]))); } jaggedvalues = GetJaggedChartValues(notes, qbchart, basetrackfaceoff2, basetrackfaceoff2, 2); foreach (uint[] faceoff in jaggedvalues) { instrument.Player2.Add(new NoteChart.Note(chart.GetTicks(faceoff[0]), chart.GetTicksDuration(faceoff[0], faceoff[1]))); } } } if (basetracktapping != null) { jaggedvalues = GetJaggedChartValues(notes, qbchart, basetracktapping, basetracktapping, 4, 4); foreach (uint[] tap in jaggedvalues) { if (instrument is NoteChart.IForcedHopo) { (instrument as NoteChart.IForcedHopo).ForceHammeron[difficulty].Add(new NoteChart.Note(chart.GetTicks(tap[0]), chart.GetTicksDuration(tap[0], tap[1]))); } } } int previouschordnum = 0; int previouschord = 0; NoteChart.Note previousnote = new NoteChart.Note(uint.MaxValue); int note32 = chart.Division.TicksPerBeat / 8; int note16 = chart.Division.TicksPerBeat / 4; values = GetChartValues(notes, qbchart, basetrack, basetrack, 4, 4); for (int k = 0; k < values.Length; k += 2) { uint fret = values[k + 1]; uint length = 0; if (notes != null) { length = fret >> 16; fret = fret & 0x0000FFFF; } else { length = fret & 0x0000FFFF; fret >>= 16; } if (notes != null) { fret = ((fret & 0xFF00) >> 8) | ((fret & 0x00FF) << 8); } NoteChart.Note note = new NoteChart.Note(chart.GetTicks(values[k]), chart.GetTicksDuration(values[k], length)); int chordnum = 0; int chord = 0; // Cut off sustains to a 32nd note before the next previousnote.Duration = (ulong)Math.Max(Math.Min((long)previousnote.Duration, (long)note.Time - (long)previousnote.Time - note16), note32); uint numfrets = 5; if (track == NoteChart.TrackType.Drums) { numfrets += 2; } int[] transform; if (notes == null) { transform = new int[] { 4, 1, 2, 3, 3, 0, -1 } } ; else { //transform = new int[] { 4, 1, 2, 3, -1, 0, 4 }; // -1 -> 4? transform = new int[] { 4, 1, 2, 3, 3, 0, 4 } }; // TODO: Verify charts for (int l = 0; l < numfrets; l++) { if (((fret >> l) & 0x01) != 0) { chordnum++; chord = l; if (track == NoteChart.TrackType.Drums) { chord = transform[l]; //if ((fret & 0x2000) != 0) // continue; //if (chord == 0 && ((fret & 0x2000) == 0) && !expertplus) // TODO: Verify expert+ // continue; } if (chord >= 0) { (instrument as NoteChart.IGems).Gems[difficulty][chord].Add(note); if (instrument is NoteChart.Drums) { ExpandDrumRoll(chart, difficulty, note, chord); } } } } if (chordnum == 0) // Bass open note, actually fret bit 6 { chordnum++; if (!(instrument is NoteChart.Drums)) { (instrument as NoteChart.IGems).Gems[difficulty][0].Add(note); } if (instrument is NoteChart.IForcedHopo) { (instrument as NoteChart.IForcedHopo).ForceHammeron[difficulty].Add(note); // Bass open notes become hopos, lulz } } else if (chordnum == 1 && chord != previouschord) { if (instrument is NoteChart.IForcedHopo) { if ((fret & 0x0040) != 0) { (instrument as NoteChart.IForcedHopo).ForceHammeron[difficulty].Add(note); } else { (instrument as NoteChart.IForcedHopo).ForceStrum[difficulty].Add(note); } } } previouschord = chord; previousnote = note; previouschordnum = chordnum; } }
public static bool ImportChart(SongData song, NoteChart chart) { ImportMap import = new ImportMap(song.Game); return(import.PopulateChart(song, chart)); }
public static PakFormat GetSongItemType(SongData song) { return(new PakFormat("", "", "", (PakFormatType)song.Data.GetValue <int>("NeversoftSongType"))); }
public override PlatformData Create(string path, Game game, ProgressIndicator progress) { PlatformData data = new PlatformData(this, game); DirectoryNode dir = data.GetDirectoryStructure(path); FileNode binfile = dir.Navigate("001.bin") as FileNode; if (binfile == null) { Exceptions.Error("Unable to open Guitar Hero World Tour DLC because 001.bin is missing."); } data.Session["rootdir"] = dir; try { DlcBin bin = new DlcBin(binfile.Data); U8 u8 = new U8(bin.Data); FileNode listfile = u8.Root.Navigate("DLC1.pak.ngc") as FileNode; Pak qb = new Pak(new EndianReader(listfile.Data, Endianness.BigEndian)); FileNode songlistfile = qb.Root.Find("catalog_info.qb.ngc", SearchOption.AllDirectories) as FileNode; QbFile songlist = new QbFile(songlistfile.Data, PakFormat); StringList strings = new StringList(); foreach (Pak.Node node in qb.Nodes) { if (!node.Filename.HasValue()) { strings.ParseFromStream(node.Data); } } List <QbKey> listkeys = new List <QbKey>(); foreach (uint songlistkey in NeversoftMetadata.SonglistKeys) { QbKey key = QbKey.Create(songlistkey); QbItemStruct list = songlist.FindItem(key, true) as QbItemStruct; if (list != null && list.Items.Count > 0) { listkeys.Add(key); } } Stream str = new FileStream(@"C:\ghwt.xml", FileMode.Create); StreamWriter writer = new StreamWriter(str); progress.NewTask(listkeys.Count); foreach (QbKey songlistkey in listkeys) { QbItemStruct list = songlist.FindItem(songlistkey, true) as QbItemStruct; progress.NewTask(list.Items.Count); foreach (QbItemArray item in list.Items.OfType <QbItemArray>()) { item.Items[0].ItemQbKey = item.ItemQbKey; SongData song = NeversoftMetadata.GetSongData(data, item.Items[0] as QbItemStruct, strings); writer.WriteLine("\t<song id=\"" + song.ID + "\">"); writer.WriteLine("\t\t<pack>Guitar Hero World Tour DLC</pack>"); writer.WriteLine("\t\t<nameprefix>[GHWT DLC]</nameprefix>"); writer.WriteLine("\t\t<name>" + song.Name + "</name>"); writer.WriteLine("\t\t<artist>" + song.Artist + "</artist>"); writer.WriteLine("\t\t<album>" + song.Album + "</album>"); writer.WriteLine("\t\t<genre>" + song.Genre + "</genre>"); writer.WriteLine("\t\t<track>" + song.AlbumTrack.ToString() + "</track>"); writer.WriteLine("\t\t<difficulty instrument=\"band\" rank=\"1\" />"); writer.WriteLine("\t\t<difficulty instrument=\"guitar\" rank=\"1\" />"); writer.WriteLine("\t\t<difficulty instrument=\"bass\" rank=\"1\" />"); writer.WriteLine("\t\t<difficulty instrument=\"drum\" rank=\"1\" />"); writer.WriteLine("\t\t<difficulty instrument=\"vocals\" rank=\"1\" />"); writer.WriteLine("\t</song>"); try { AddSong(data, song, progress); } catch (Exception exception) { Exceptions.Warning(exception, "Unable to properly parse " + song.Name); } progress.Progress(); } progress.EndTask(); progress.Progress(); } progress.EndTask(); writer.Close(); binfile.Data.Close(); } catch (Exception exception) { Exceptions.Error(exception, "An error occurred while parsing the Guitar Hero World Tour DLC list."); } return(data); }
public InstrumentDifficulty(SongData data) { Data = data; }
public static SongData GetSongData(PlatformData platformdata, QbItemStruct item, StringList strings) { if (strings == null) { strings = new StringList(); } SongData data = new SongData(platformdata); data.ID = GetSongDataString(item, QbKeysID, strings); data.Name = GetSongDataString(item, QbKeysName, strings); data.Artist = GetSongDataString(item, QbKeysArtist, strings); data.Album = GetSongDataString(item, QbKeysAlbum, strings); if (strings.FindItem(QbKey.Create(QbKeysGenres[0].Key[0])) == null) { strings.Items.AddRange(QbKeysGenres.Select(g => new KeyValuePair <QbKey, string>(QbKey.Create(g.Key[0]), g.Value))); // TODO: Expand the Key array } data.Genre = GetSongDataString(item, QbKeysGenre, strings); QbItemInteger year = GetQbItem(item, QbKeysYear) as QbItemInteger; if (year != null) { data.Year = (int)year.Values[0]; } else { int yearnum; if (int.TryParse(GetSongDataString(item, QbKeysYear, strings).TrimStart(',', ' '), out yearnum)) // ", 2009" { data.Year = yearnum; } } QbItemInteger master = GetQbItem(item, QbKeysMaster) as QbItemInteger; if (master != null) { data.Master = master.Values[0] == 1; } QbItemInteger rank = GetQbItem(item, QbKeysDifficulty[Instrument.Ambient]) as QbItemInteger; if (rank != null) { data.Difficulty[Instrument.Ambient] = (int)rank.Values[0] * 60; } rank = GetQbItem(item, QbKeysDifficulty[Instrument.Drums]) as QbItemInteger; if (rank != null) { data.Difficulty[Instrument.Drums] = (int)rank.Values[0] * 50; } rank = GetQbItem(item, QbKeysDifficulty[Instrument.Vocals]) as QbItemInteger; if (rank != null) { data.Difficulty[Instrument.Vocals] = (int)rank.Values[0] * 45; } rank = GetQbItem(item, QbKeysDifficulty[Instrument.Bass]) as QbItemInteger; if (rank != null) { data.Difficulty[Instrument.Bass] = (int)rank.Values[0] * 55; } rank = GetQbItem(item, QbKeysDifficulty[Instrument.Guitar]) as QbItemInteger; if (rank != null) { data.Difficulty[Instrument.Guitar] = (int)rank.Values[0] * 60; } QbKey vocalmale = QbKey.Create(0xAA721F56); QbKey vocalfemale = QbKey.Create("female"); if (strings.FindItem(vocalmale) == null) { strings.Items.Add(new KeyValuePair <QbKey, string>(vocalmale, "male")); } if (strings.FindItem(vocalfemale) == null) { strings.Items.Add(new KeyValuePair <QbKey, string>(vocalfemale, "female")); } data.Vocalist = GetSongDataString(item, QbKeysVocalist, strings); if (!data.Vocalist.HasValue()) { data.Vocalist = "male"; } QbItemFloat hopo = GetQbItem(item, QbKeysHopo) as QbItemFloat; if (hopo != null) { data.HopoThreshold = (int)((float)NoteChart.DefaultTicksPerBeat / hopo.Values[0]); } // TODO: Better handling of QB items; this uses up a shitload of memory MemoryStream itemstream = new MemoryStream(); item.Root.Write(itemstream); data.Data.SetValue("NeversoftSongItem", itemstream.GetBuffer()); data.Data.SetValue("NeversoftSongType", (int)item.Root.PakFormat.PakFormatType); data.Data.SetValue("NeversoftSongItemKey", item.ItemQbKey.Crc); return(data); }
public static ushort[] RemixAudioTracks(SongData song, AudioFormat audioformat) { // Audio tracks must match up with the tiers; disabled instruments (tier 0) must have no audio tracks. List <ushort> masks = new List <ushort>(); List <AudioFormat.Mapping> newmaps = new List <AudioFormat.Mapping>(); foreach (Instrument instrument in new Instrument[] { Instrument.Drums, Instrument.Bass, Instrument.Guitar, Instrument.Vocals, Instrument.Ambient }) { List <AudioFormat.Mapping> maps = new List <AudioFormat.Mapping>(); foreach (var map in audioformat.Mappings) { if (map.Instrument == instrument && song.Difficulty[instrument] == 0) { map.Instrument = Instrument.Ambient; } if (map.Instrument == instrument) { maps.Add(map); } } if (maps.Count == 0 && song.Difficulty[instrument] > 0) { newmaps.Add(new AudioFormat.Mapping(0, instrument == Instrument.Drums ? -1 : 0, instrument)); masks.Add(0); if (instrument == Instrument.Drums) { newmaps.Add(new AudioFormat.Mapping(0, 1, instrument)); masks.Add(0); } } else if (maps.Count > 2 && instrument != Instrument.Drums) { ushort[] submasks = new ushort[2]; foreach (var map in maps) { int index = audioformat.Mappings.IndexOf(map); if (map.Balance <= 0) { submasks[0] |= (ushort)(1 << index); } if (map.Balance >= 0) { submasks[1] |= (ushort)(1 << index); } } if (submasks[0] == submasks[1]) { newmaps.Add(new AudioFormat.Mapping(0, 0, instrument)); masks.Add(submasks[0]); } else { newmaps.Add(new AudioFormat.Mapping(0, -1, instrument)); masks.Add(submasks[0]); newmaps.Add(new AudioFormat.Mapping(0, 1, instrument)); masks.Add(submasks[1]); } } else if (maps.Count != 0) { foreach (var map in maps) { newmaps.Add(map); masks.Add((ushort)(1 << audioformat.Mappings.IndexOf(map))); } } } audioformat.Mappings = newmaps; return(masks.ToArray()); }
public override void SaveSong(PlatformData data, FormatData formatdata, ProgressIndicator progress) { string path = data.Session["maindirpath"] as string; string otitle; ushort oindex; progress.NewTask(10); using (DelayedStreamCache cache = new DelayedStreamCache()) { progress.SetNextWeight(6); string audioextension = ".mogg"; Stream audio = null; Stream preview = null; AudioFormat audioformat = null; IList <IFormat> formats = formatdata.Formats; if (formats.Contains(AudioFormatRB2Mogg.Instance)) { audio = AudioFormatRB2Mogg.Instance.GetAudioStream(formatdata); preview = AudioFormatRB2Mogg.Instance.GetPreviewStream(formatdata); audioformat = AudioFormatRB2Mogg.Instance.DecodeAudioFormat(formatdata); } else if (formats.Contains(AudioFormatRB2Bink.Instance)) { audio = AudioFormatRB2Bink.Instance.GetAudioStream(formatdata); preview = AudioFormatRB2Bink.Instance.GetPreviewStream(formatdata, progress); if (!formatdata.HasStream(preview)) { cache.AddStream(preview); } audioformat = AudioFormatRB2Bink.Instance.DecodeAudioFormat(formatdata); audioextension = ".bik"; } else { throw new NotSupportedException(); } progress.Progress(6); ChartFormat chartformat = (formatdata.GetFormat(FormatType.Chart) as IChartFormat).DecodeChart(formatdata, progress); Stream album = null; Stream chart = formatdata.GetStream(ChartFormatRB.Instance, ChartFormatRB.ChartFile); Stream pan = formatdata.GetStream(ChartFormatRB.Instance, ChartFormatRB.PanFile); Stream weights = formatdata.GetStream(ChartFormatRB.Instance, ChartFormatRB.WeightsFile); Stream milo = formatdata.GetStream(ChartFormatRB.Instance, ChartFormatRB.MiloFile); progress.SetNextWeight(2); if (chart != null && ChartFormatRB.Instance.NeedsFixing(formatdata)) { formatdata.CloseStream(chart); chart = null; } if (chart == null) { chart = new TemporaryStream(); cache.AddStream(chart); AdjustChart(formatdata.Song, audioformat, chartformat).ToMidi().ToMid().Save(chart); chart.Position = 0; } if (weights == null) { weights = new TemporaryStream(); cache.AddStream(weights); CreateWeights(weights, chartformat); weights.Position = 0; } if (pan == null) { pan = new TemporaryStream(); cache.AddStream(pan); CreatePan(pan, chartformat); pan.Position = 0; } if (milo == null) { milo = formatdata.GetStream(ChartFormatRB.Instance, ChartFormatRB.Milo3File); if (milo == null) { milo = new MemoryStream(Properties.Resources.rawksd_milo); } else { Stream milostream = new TemporaryStream(); cache.AddStream(milostream); Milo milofile = new Milo(new EndianReader(milo, Endianness.LittleEndian)); FaceFX fx = new FaceFX(new EndianReader(milofile.Data[0], Endianness.BigEndian)); TemporaryStream fxstream = new TemporaryStream(); fx.Save(new EndianReader(fxstream, Endianness.LittleEndian)); milofile.Data[0] = fxstream; milofile.Compressed = true; milofile.Save(new EndianReader(milostream, Endianness.LittleEndian)); fxstream.Close(); formatdata.CloseStream(milo); milo = milostream; milo.Position = 0; } } //if (album == null) // album = new MemoryStream(Properties.Resources.rawksd_albumart); progress.Progress(2); SongData song = new SongData(formatdata.Song); SongsDTA dta = GetSongsDTA(song, audioformat); if (album == null) { dta.AlbumArt = false; } else { dta.AlbumArt = true; } dta.Song.MidiFile = "dlc/content/songs/" + song.ID + "/" + song.ID + ".mid"; DTB.NodeTree dtb = dta.ToDTB(PlatformRawkFile.Instance.IsRawkSD2(song)); MemoryStream songsdta = new MemoryStream(); cache.AddStream(songsdta); dtb.SaveDTA(songsdta); songsdta.Position = 0; U8 appdta = new U8(); DirectoryNode dir = new DirectoryNode("content"); appdta.Root.AddChild(dir); DirectoryNode songsdir = new DirectoryNode("songs"); dir.AddChild(songsdir); DirectoryNode songdir = new DirectoryNode(song.ID); songsdir.AddChild(songdir); songdir.AddChild(new FileNode(song.ID + "_prev.mogg", preview)); songdir.AddChild(new FileNode("songs.dta", songsdta)); DirectoryNode gendir; if (dta.AlbumArt.Value && album != null) { gendir = new DirectoryNode("gen"); songdir.AddChild(gendir); gendir.AddChild(new FileNode(song.ID + "_nomip_keep.bmp_wii", album)); } U8 appsong = new U8(); dir = new DirectoryNode("content"); appsong.Root.AddChild(dir); songsdir = new DirectoryNode("songs"); dir.AddChild(songsdir); songdir = new DirectoryNode(song.ID); songsdir.AddChild(songdir); songdir.AddChild(new FileNode(song.ID + audioextension, audio)); songdir.AddChild(new FileNode(song.ID + ".mid", chart)); songdir.AddChild(new FileNode(song.ID + ".pan", pan)); gendir = new DirectoryNode("gen"); songdir.AddChild(gendir); gendir.AddChild(new FileNode(song.ID + ".milo_wii", milo)); gendir.AddChild(new FileNode(song.ID + "_weights.bin", weights)); Stream memoryDta = new TemporaryStream(); cache.AddStream(memoryDta); appdta.Save(memoryDta); Stream memorySong = new TemporaryStream(); cache.AddStream(memorySong); appsong.Save(memorySong); formatdata.CloseStream(audio); formatdata.CloseStream(preview); formatdata.CloseStream(chart); formatdata.CloseStream(album); formatdata.CloseStream(pan); formatdata.CloseStream(weights); formatdata.CloseStream(milo); FindUnusedContent(data, formatdata.Song, out otitle, out oindex); TMD tmd = GenerateDummyTMD(otitle); dta.Song.Name = "dlc/" + otitle + "/" + Util.Pad(oindex.ToString(), 3) + "/content/songs/" + song.ID + "/" + song.ID; dtb = dta.ToDTB(PlatformRawkFile.Instance.IsRawkSD2(song)); HarmonixMetadata.SetSongsDTA(song, dtb); string dirpath = Path.Combine(Path.Combine(path, "rawk"), "rb2"); if (!Directory.Exists(Path.Combine(dirpath, "customs"))) { Directory.CreateDirectory(Path.Combine(dirpath, "customs")); } Directory.CreateDirectory(Path.Combine(Path.Combine(dirpath, "customs"), song.ID)); FileStream savestream = new FileStream(Path.Combine(Path.Combine(Path.Combine(dirpath, "customs"), song.ID), "data"), FileMode.Create); dtb.Save(new EndianReader(savestream, Endianness.LittleEndian)); savestream.Close(); TmdContent contentDta = new TmdContent(); contentDta.ContentID = oindex; contentDta.Index = oindex; contentDta.Type = 0x4001; TmdContent contentSong = new TmdContent(); contentSong.ContentID = oindex + 1U; contentSong.Index = (ushort)(oindex + 1); contentSong.Type = 0x4001; memoryDta.Position = 0; contentDta.Hash = Util.SHA1Hash(memoryDta); contentDta.Size = memoryDta.Length; memorySong.Position = 0; contentSong.Hash = Util.SHA1Hash(memorySong); contentSong.Size = memorySong.Length; for (int i = 1; i <= oindex + 1; i++) { if (i == oindex) { tmd.Contents.Add(contentDta); } else if (i == oindex + 1) { tmd.Contents.Add(contentSong); } else { tmd.Contents.Add(new TmdContent() { Index = (ushort)i, ContentID = (uint)i, Size = 1, Type = 0x4001 }); } } tmd.Fakesign(); uint consoleid = GetConsoleID(path); progress.Progress(); dirpath = Path.Combine(Path.Combine(Path.Combine(Path.Combine(path, "private"), "wii"), "data"), "sZAE"); TemporaryStream binstream; DlcBin bin; if (consoleid != 0 && !File.Exists(Path.Combine(dirpath, "000.bin"))) { Directory.CreateDirectory(dirpath); binstream = new TemporaryStream(); binstream.Write(Properties.Resources.rawksd_000bin, 0, Properties.Resources.rawksd_000bin.Length); binstream.Position = 8; new EndianReader(binstream, Endianness.BigEndian).Write(consoleid); binstream.ClosePersist(); File.Move(binstream.Name, Path.Combine(dirpath, "000.bin")); binstream.Close(); } dirpath = Path.Combine(Path.Combine(Path.Combine(Path.Combine(path, "private"), "wii"), "data"), otitle); if (!Directory.Exists(dirpath)) { Directory.CreateDirectory(dirpath); } binstream = new TemporaryStream(); bin = new DlcBin(); bin.Bk.ConsoleID = consoleid; bin.TMD = tmd; bin.Content = tmd.Contents[oindex]; bin.Data = memoryDta; bin.Generate(); bin.Bk.ContentSize = bin.Bk.TotalSize = 0; bin.Bk.TitleID = 0x00010000535A4145UL; bin.Save(binstream); binstream.ClosePersist(); string dtabinpath = Path.Combine(dirpath, Util.Pad(oindex.ToString(), 3) + ".bin"); Util.Delete(dtabinpath); File.Move(binstream.Name, dtabinpath); binstream.Close(); binstream = new TemporaryStream(); bin = new DlcBin(); bin.Bk.ConsoleID = consoleid; bin.TMD = tmd; bin.Content = tmd.Contents[oindex + 1]; bin.Data = memorySong; bin.Generate(); bin.Bk.ContentSize = bin.Bk.TotalSize = 0; bin.Bk.TitleID = 0x00010000535A4145UL; bin.Save(binstream); binstream.ClosePersist(); string songbinpath = Path.Combine(dirpath, Util.Pad((oindex + 1).ToString(), 3) + ".bin"); Util.Delete(songbinpath); File.Move(binstream.Name, songbinpath); binstream.Close(); data.Mutex.WaitOne(); string mainbinpath = Path.Combine(dirpath, "000.bin"); if (!File.Exists(mainbinpath)) { binstream = new TemporaryStream(); bin = new DlcBin(); bin.Bk.ConsoleID = consoleid; bin.TMD = tmd; bin.Content = tmd.Contents[0]; bin.Data = new MemoryStream(Properties.Resources.rawksd_savebanner, false); bin.Generate(); bin.Bk.TitleID = 0x00010000535A4145UL; bin.Save(binstream); binstream.ClosePersist(); File.Move(binstream.Name, mainbinpath); binstream.Close(); } AddSongFromBins(data, song, dtabinpath, songbinpath, progress, true); SaveDTBCache(data); data.Mutex.ReleaseMutex(); cache.Dispose(); progress.Progress(); } progress.EndTask(); }
public ChartFormat DecodeChart(FormatData data, ProgressIndicator progress, params Stream[] chartstreams) { progress.NewTask(5 + 12); PakFormat format = NeversoftMetadata.GetSongItemType(data.Song); SongData song = NeversoftMetadata.GetSongData(data.PlatformData, NeversoftMetadata.GetSongItem(data)); List <Pak> chartpaks = new List <Pak>(); foreach (Stream stream in chartstreams) { chartpaks.Add(new Pak(new EndianReader(stream, Endianness.BigEndian))); // TODO: Endianness based on format? } FileNode chartfile = null; foreach (Pak pak in chartpaks) { chartfile = pak.FindFile(song.ID + ".mid.qb.ngc") ?? chartfile; chartfile = pak.FindFile(song.ID + ".mid.qb") ?? chartfile; } if (chartfile == null) { foreach (Pak pak in chartpaks) { chartfile = chartfile ?? pak.FindFileType(0xa7f505c4); } } QbFile qbchart = null; if (chartfile != null) { qbchart = new QbFile(chartfile.Data, format); } StringList strings = new StringList(); foreach (Pak pak in chartpaks) { foreach (Pak.Node n in pak.Nodes) { if (!n.Filename.HasValue()) { strings.ParseFromStream(n.Data); } } } QbFile qbsections = null; FileNode qbsectionfile = null; foreach (Pak pak in chartpaks) { qbsectionfile = pak.FindFile(song.ID + ".mid_text.qb.ngc") as FileNode ?? qbsectionfile; qbsectionfile = pak.FindFile(song.ID + ".mid_text.qb") as FileNode ?? qbsectionfile; } if (qbsectionfile != null) { qbsections = new QbFile(qbsectionfile.Data, format); } Notes notes = null; FileNode notesfile = null; foreach (Pak pak in chartpaks) { notesfile = notesfile ?? pak.FindFileType(0xa9d5bc8f); notesfile = pak.FindFile(song.ID + ".note.ngc") as FileNode ?? notesfile; notesfile = pak.FindFile(song.ID + ".note") as FileNode ?? notesfile; } if (notesfile == null) { foreach (Pak pak in chartpaks) { notesfile = pak.FindFileType(0xa9d5bc8f) ?? notesfile; } } if (notesfile != null) { notesfile.Data.Position = 0; notes = Notes.Create(new EndianReader(notesfile.Data, Endianness.BigEndian)); } NoteChart chart = new NoteChart(); chart.PartGuitar = new NoteChart.Guitar(chart); chart.PartBass = new NoteChart.Bass(chart); chart.PartDrums = new NoteChart.Drums(chart); chart.PartVocals = new NoteChart.Vocals(chart); chart.Events = new NoteChart.EventsTrack(chart); chart.Venue = new NoteChart.VenueTrack(chart); chart.Beat = new NoteChart.BeatTrack(chart); bool gh4v2 = NeversoftMetadata.IsGuitarHero4(data.PlatformData.Game) && data.PlatformData.Game != Game.GuitarHeroWorldTour; string drumconfig = gh4v2 ? "drums3" : "drums2"; chart.PartDrums.Mixing.Add(new Pair <NoteChart.Point, Pair <NoteChart.Difficulty, string> >(new NoteChart.Point(0), new Pair <NoteChart.Difficulty, string>(NoteChart.Difficulty.Easy, drumconfig + "easy"))); chart.PartDrums.Mixing.Add(new Pair <NoteChart.Point, Pair <NoteChart.Difficulty, string> >(new NoteChart.Point(0), new Pair <NoteChart.Difficulty, string>(NoteChart.Difficulty.Medium, drumconfig))); chart.PartDrums.Mixing.Add(new Pair <NoteChart.Point, Pair <NoteChart.Difficulty, string> >(new NoteChart.Point(0), new Pair <NoteChart.Difficulty, string>(NoteChart.Difficulty.Hard, drumconfig))); chart.PartDrums.Mixing.Add(new Pair <NoteChart.Point, Pair <NoteChart.Difficulty, string> >(new NoteChart.Point(0), new Pair <NoteChart.Difficulty, string>(NoteChart.Difficulty.Expert, drumconfig))); progress.Progress(); DecodeChartFretbars(song, qbchart, notes, chart); progress.Progress(); DecodeChartSections(song, qbchart, strings, qbsections, notes, chart); progress.Progress(); for (NoteChart.TrackType track = NoteChart.TrackType.Guitar; track <= NoteChart.TrackType.Drums;) { for (NoteChart.Difficulty difficulty = NoteChart.Difficulty.Easy; difficulty <= NoteChart.Difficulty.Expert; difficulty++) { DecodeChartNotes(song, qbchart, notes, chart, track, difficulty); progress.Progress(); } switch (track) { case NoteChart.TrackType.Guitar: track = NoteChart.TrackType.Bass; break; case NoteChart.TrackType.Bass: track = NoteChart.TrackType.Drums; break; case NoteChart.TrackType.Drums: track = NoteChart.TrackType.Events; break; } } // Automatic Drum Fills - 1-measure fills every 4 measures, if there's no overdrive overlap FillSections(chart, 1, 4, 3, chart.PartDrums.DrumFills, chart.PartDrums.Overdrive); progress.Progress(); if (DecodeChartVocals(song, qbchart, strings, notes, chart)) { DecodeChartVocalPhrases(song, qbchart, notes, chart); } ImportMap.ImportChart(data.Song, chart); progress.Progress(); progress.EndTask(); return(new ChartFormat(chart)); }
public bool IsRawkSD2(SongData song) { return(song.Data.GetValue <bool>("RawkSD2Compatibility") || song.Version == 0); }
public static AudioFormat GetAudioFormat(FormatData data) { SongData song = data.Song; AudioFormat audioformat = new AudioFormat(); QbItemStruct item = GetSongItem(data); if (item == null) { return(null); } float bandvolume = 0; float guitarvolume = 0; float bassvolume = 0; float drumvolume = 0; QbItemFloat subitem = item.FindItem(QbKey.Create(0xD8F335CF), false) as QbItemFloat; // GH3: band_playback_volume if (subitem != null) { bandvolume = (subitem as QbItemFloat).Values[0]; bassvolume = bandvolume; } subitem = item.FindItem(QbKey.Create(0xA449CAD3), false) as QbItemFloat; // GH3: guitar_playback_volume if (subitem != null) { guitarvolume = (subitem as QbItemFloat).Values[0]; } subitem = item.FindItem(QbKey.Create(0x46507438), false) as QbItemFloat; // GH4: overall_song_volume if (subitem != null) { bandvolume = (subitem as QbItemFloat).Values[0]; guitarvolume = bandvolume; bassvolume = bandvolume; drumvolume = bandvolume; } // GH4 engine games that came out after GHWT use a different drum audio scheme; the GH5 engine uses the same as GHWT bool gh4v2 = NeversoftMetadata.IsGuitarHero4(song.Game) && song.Game != Game.GuitarHeroWorldTour; // GHVH is the only BIK-based GH game with stereo bass bool ghvh = song.Game == Game.GuitarHeroVanHalen; if (gh4v2) { // Kick audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, -1, Instrument.Drums)); audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, 1, Instrument.Drums)); // Snare audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, -1, Instrument.Drums)); audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, 1, Instrument.Drums)); } else { // Kick audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, 0, Instrument.Drums)); // Snare audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, 0, Instrument.Drums)); } // Overhead audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, -1, Instrument.Drums)); audioformat.Mappings.Add(new AudioFormat.Mapping(drumvolume, 1, Instrument.Drums)); // Guitar audioformat.Mappings.Add(new AudioFormat.Mapping(guitarvolume, -1, Instrument.Guitar)); audioformat.Mappings.Add(new AudioFormat.Mapping(guitarvolume, 1, Instrument.Guitar)); // Bass audioformat.Mappings.Add(new AudioFormat.Mapping(bassvolume, ghvh ? -1 : 0, Instrument.Bass)); if (ghvh) { audioformat.Mappings.Add(new AudioFormat.Mapping(bassvolume, 1, Instrument.Bass)); } // Else / Vocals audioformat.Mappings.Add(new AudioFormat.Mapping(bandvolume, -1, Instrument.Ambient)); audioformat.Mappings.Add(new AudioFormat.Mapping(bandvolume, 1, Instrument.Ambient)); // Preview audioformat.Mappings.Add(new AudioFormat.Mapping(bandvolume, -1, Instrument.Preview)); audioformat.Mappings.Add(new AudioFormat.Mapping(bandvolume, 1, Instrument.Preview)); return(audioformat); }
public override bool AddSong(PlatformData data, SongData song, ProgressIndicator progress) { throw new NotImplementedException(); }
public bool Populate(SongData song) { bool ret = false; string idprefix = string.Empty; string nameprefix = string.Empty; string songid = song.ID; if (Root == null) { goto populateend; } foreach (XmlElement node in Root.GetElementsByTagName("global")) { song.PopulateFromXML(node as XmlElement, RootPath); ret = true; foreach (XmlElement element in node.GetElementsByTagName("idprefix")) { idprefix = element.InnerText; } foreach (XmlElement element in node.GetElementsByTagName("nameprefix")) { nameprefix = element.InnerText; } } if (songid.StartsWith(idprefix)) { songid = songid.Substring(idprefix.Length); } foreach (XmlElement element in Root.GetElementsByTagName("song")) { if (element.Attributes["game"] != null && int.Parse(element.Attributes["game"].Value) != (int)Game) { continue; } if (string.Compare(element.Attributes["id"].Value, songid, true) == 0) { song.PopulateFromXML(element, RootPath); ret = true; goto populateend; } } populateend: if (songid == song.ID) { if (idprefix.Length > 0) { song.ID = idprefix + song.ID; } if (nameprefix.Length > 0) { switch (ApplyNamePrefix) { case NamePrefix.Prefix: song.Name = nameprefix + " " + song.Name; break; case NamePrefix.Postfix: song.Name = song.Name + " " + nameprefix; break; } } } if (!song.Pack.HasValue() && song.Game != Game.Unknown) { song.Pack = Platform.GameName(song.Game); } return(ret); }
public static AudioFormat GetAudioFormat(SongData song) { throw new NotImplementedException(); }
private bool DecodeChartVocals(SongData song, QbFile qbchart, StringList strings, Notes notes, NoteChart chart) { uint[] values = GetChartValues(notes, qbchart, QbKey.Create(0xE8E6ADCB), QbKey.Create(song.ID + "_song_vocals"), 4, 2, 1); for (int k = 0; k < values.Length; k += 3) { byte note = (byte)values[k + 2]; if (note != 2) { if (note > 84) { note -= 12; } chart.PartVocals.Gems.Add(new Midi.NoteEvent(chart.GetTicks(values[k]), 0, note, 100, chart.GetTicksDuration(values[k], values[k + 1]))); } } List <Pair <NoteChart.Point, string> > vlyrics = new List <Pair <NoteChart.Point, string> >(); if (notes != null) { byte[][] vdata = notes.Find(QbKey.Create(0x1DA27F4E)).Data; foreach (byte[] d in vdata) { EndianReader reader = new EndianReader(new MemoryStream(d), Endianness.BigEndian); uint time = reader.ReadUInt32(); string lyric = reader.ReadString(); vlyrics.Add(new Pair <NoteChart.Point, string>( new NoteChart.Point(chart.GetTicks(time)), lyric )); } } else { QbItemStructArray lyrics = (qbchart.FindItem(QbKey.Create(song.ID + "_lyrics"), false) as QbItemArray).Items[0] as QbItemStructArray; if (lyrics != null) { foreach (QbItemBase item in lyrics.Items) { string lyric = strings.FindItem((item.Items[1] as QbItemQbKey).Values[0]); vlyrics.Add(new Pair <NoteChart.Point, string>( new NoteChart.Point(chart.GetTicks((item.Items[0] as QbItemInteger).Values[0])), lyric )); } } } Pair <NoteChart.Point, string> lastlyric = null; foreach (var item in vlyrics) { string lyric = item.Value; if (lyric.StartsWith("=") && lastlyric != null) { if (lastlyric.Value.EndsWith("-")) { lastlyric.Value = lastlyric.Value.Substring(0, lastlyric.Value.Length - 1) + '='; } else { lastlyric.Value += "-"; } lyric = lyric.Substring(1); } lastlyric = new Pair <NoteChart.Point, string>( item.Key, lyric ); chart.PartVocals.Lyrics.Add(lastlyric); } foreach (Midi.NoteEvent item in chart.PartVocals.Gems) { bool found = false; foreach (Pair <NoteChart.Point, string> lyric in chart.PartVocals.Lyrics) { if (lyric.Key.Time == item.Time) { if (item.Note == 26) { lyric.Value += "#"; item.Note = 36; } found = true; break; } } if (!found) { chart.PartVocals.Lyrics.Add(new Pair <NoteChart.Point, string>(new NoteChart.Point(item.Time), "+")); } } __goddamnremovals: //Midi.NoteEvent lastnote = null; foreach (Pair <NoteChart.Point, string> lyric in chart.PartVocals.Lyrics) { bool found = false; foreach (Midi.NoteEvent item in chart.PartVocals.Gems) { if (lyric.Key.Time == item.Time) { found = true; break; } } if (!found) { /* * ulong duration = chart.GetTicksDuration(chart.GetTime(lyric.Key.Time) / 1000, 30); * if (lastnote != null && lastnote.Time + lastnote.Duration > lyric.Key.Time) * lastnote.Duration = lyric.Key.Time - lastnote.Time - 20; * lastnote = new Midi.NoteEvent(lyric.Key.Time, 0, 36, 100, duration); * chart.PartVocals.Gems.Add(lastnote); * lyric.Value += "^"; */ chart.PartVocals.Lyrics.Remove(lyric); goto __goddamnremovals; } } if (chart.PartVocals.Gems.Count == 0) { chart.PartVocals = null; return(false); } return(true); }