private int replaceNotesItems()
{
int notesLength = 0; //position of final notes item (last fret)
QbKey song = this.SongQb.Id;
string songName = song.Text;
GameFile gf = _project.FileManager.File(_project.GameInfo.GetNotesFilename(song));
if (gf == null)
return notesLength; //return 0, this prevents exceptions in the ISO tool which doesn't replace notes
string notesPak = gf.LocalName;
PakFormat pf = new PakFormat(notesPak, "", "", _project.GameInfo.PakFormatType);
PakEditor pak = new PakEditor(pf);
QbFile qb = pak.ReadQbFile(_project.GameInfo.GetNotesQbFilename(song));
//modify the mid file
//clearAllQbItems(qb, this.Notes.GhItems,
// QbKey.Create(string.Format("{0}_TimeSig", songName)),
// QbKey.Create(string.Format("{0}_FretBars", songName)),
// QbKey.Create(string.Format("{0}_Markers", songName)));
QbFile qbText;
if (!_project.GameInfo.MidTextInQbPak)
qbText = pak.ReadQbFile(_project.GameInfo.GetNotesTextQbFilename(song));
else
{
qbText = _project.FileManager.QbPakEditor.ReadQbFile(_project.GameInfo.GetNotesTextQbFilename(song));
}
QbItemArray ar;
int[] ints;
int offset;
//calculate ms to add to wav to ensure notes don't start before the given time (in seconds)
if (this.Notes.MinNoteOffsetSynced < this.MinMsBeforeNotesStart)
_startPaddingMs = this.MinMsBeforeNotesStart - this.Notes.MinNoteOffsetSynced;
this.Length = this.Audio.AudioLength + _startPaddingMs;
offset = this.Notes.BaseFile.NonNoteSyncOffset + _startPaddingMs;
int[] frets = (int[])this.Notes.BaseFile.Frets.Clone(); //clone in case class is holding reference
for (int i = 0; i < frets.Length; i++)
frets[i] += offset;
//this function sets _fretPadding, another padding value. It adds padding to allow a properly spaced fret to be at position 0
frets = adjustFrets(frets);
notesLength = frets[frets.Length - 1];
//set the track length to the notes length if it's longer
if (this.Length < notesLength)
this.Length = notesLength;
else
this.Length += _fretPadding;
offset += _fretPadding;
int[] timeSig = (int[])this.Notes.BaseFile.Parser.GetTimeSig().Clone(); //clone in case class is holding reference
if (timeSig.Length == 0)
timeSig = new int[] { 0, 4, 4 };
for (int i = 0; i < timeSig.Length; i += 3)
timeSig[i] = (int)findNearestFret((uint)(timeSig[i] + offset), frets);
timeSig[0] = 0; //if the first item is not 0 the song won't load??.
NotesMarker[] markers = (NotesMarker[])this.Notes.BaseFile.Parser.GetNotesMarkers().Clone(); //clone in case class is holding reference
for (int i = 0; i < markers.Length; i += 3)
markers[i] = new NotesMarker(markers[i].Title, markers[i].Offset + offset); //perform deep clone
int oldSustainTrigger;
int sustainTrigger;
int nextNote;
int[] faceOffP1Ints = new int[0];
int[] faceOffP2Ints = new int[0];
GhNotesItem faceOffItem = null;
//we have a face off item for each mapping, GH3 only has one per song, find the one with the hardest difficulty (They're always the same anyway)
foreach (GhNotesItem ghi in this.Notes.GhItems)
{
if (ghi.IsMapped && ghi.MappedFileItem.FaceOffP1Count != 0 && ghi.MappedFileItem.FaceOffP2Count != 0)
{
//non generated overrides generated
if (faceOffItem == null || faceOffItem.MappedFileItem.HasGeneratedFaceOff || (ghi.MappedFileItem.HasGeneratedFaceOff == faceOffItem.MappedFileItem.HasGeneratedFaceOff))
{
if (faceOffItem == null || ((int)faceOffItem.Difficulty < (int)ghi.Difficulty && ghi.Type == NotesType.Guitar)) //guitar is more reliable
faceOffItem = ghi;
}
}
}
if (faceOffItem != null)
{
offset = faceOffItem.MappedFileItem.SyncOffset + _startPaddingMs + _fretPadding;
faceOffP1Ints = (int[])faceOffItem.MappedFileItem.FaceOffP1.Clone();
for (int i = 0; i < faceOffP1Ints.Length; i += 2)
faceOffP1Ints[i] += offset;
faceOffP2Ints = (int[])faceOffItem.MappedFileItem.FaceOffP2.Clone();
for (int i = 0; i < faceOffP2Ints.Length; i += 2)
faceOffP2Ints[i] += offset;
}
foreach (GhNotesItem ghi in this.Notes.GhItems)
{
if (ghi.IsMapped)
{
oldSustainTrigger = ghi.MappedFileItem.SustainTrigger;
sustainTrigger = (int)((float)(frets[1] - frets[0]) / 2F);
ghi.MappedFileItem.SustainTrigger = sustainTrigger;
//Offset notes
offset = ghi.MappedFileItem.SyncOffset + _startPaddingMs + _fretPadding;
ints = (int[])ghi.MappedFileItem.Notes.Clone(); //don't modify original notes
int startFret = 0;
for (int i = 0; i < ints.Length; i += 3)
{
ints[i] += offset;
if (i + 3 < ints.Length)
nextNote = ints[i + 3] + offset;
else
nextNote = 0;
//loop to find fret length note is in to calculate if note is sustained
int fpos;
int fretLen = 0;
bool isSustained = false;
for (int c = startFret; c < frets.Length; c++)
{
if ((fpos = frets[c]) > ints[i] && c > 0) //careful fpos is assigned here
{
startFret = c; //next time start from here
fretLen = fpos - frets[c - 1];
isSustained = ints[i + 1] > ((fretLen / 192.0) * (double)(192 >> 2)); //(fretLen / 192.0 == bpmUnit
break;
}
}
//clip sustained notes to GH3 mode
if (isSustained)
ints[i + 1] = setSustain(ints[i], ints[i + 1], nextNote, oldSustainTrigger / 2, sustainTrigger / 2, this.Notes.Gh3SustainClipping);
}
int[] notes = ints;
//if this is a boss battle then remove notes that are not within the face off sections
if (this.IsBoss && faceOffItem != null)
ints = convertBossNotesToFaceOff(ints, ghi.Type == NotesType.Guitar ? faceOffP1Ints : faceOffP2Ints);
ints = adjustNotes(ints); //merge any notes that are really close together
//replace track notes
ar = (QbItemArray)qb.FindItem(ghi.SongNotesQbKey, false);
replaceQbItems(ar, ints, false);
setLength(ar, this.Length, 3, frets, false);
//Offset star power
ints = (int[])ghi.MappedFileItem.StarPower.Clone(); //don't modify original starpower
for (int i = 0; i < ints.Length; i += 3)
ints[i] += offset;
//if (faceOffItem != null)
// alignBattleStarPowerToFaceOff(ints, ghi.Type == NotesType.Guitar ? faceOffP1Ints : faceOffP2Ints);
ints = adjustBattleStarPower(ints, notes);
//replace star power
ar = (QbItemArray)qb.FindItem(ghi.SongStarPowerQbKey, false);
replaceQbItems(ar, this.Notes.ForceNoStarPower ? new int[0] : ints, true); //optionally set to no star power
setLength(ar, this.Length, 3, frets, false);
int[] sp = ints;
//Offset star battle mode
ints = (int[])ghi.MappedFileItem.BattlePower.Clone();
for (int i = 0; i < ints.Length; i += 3)
ints[i] += offset;
//if (faceOffItem != null)
// alignBattleStarPowerToFaceOff(ints, ghi.Type == NotesType.Guitar ? faceOffP1Ints : faceOffP2Ints);
ints = adjustBattleStarPower(ints, notes);
if (ints.Length == 0) //if no ints then use star power
ints = (int[])sp.Clone(); //just to ensure there's no issue with 2 references pointing at the same array
//replace star battle notes
ar = (QbItemArray)qb.FindItem(ghi.SongStarPowerBattleQbKey, false);
replaceQbItems(ar, ints, true);
setLength(ar, this.Length, 3, frets, false);
}
else
{
ar = (QbItemArray)qb.FindItem(ghi.SongNotesQbKey, false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(ghi.SongStarPowerQbKey, false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(ghi.SongStarPowerBattleQbKey, false);
clearQbItems(ar);
}
}
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_GuitarCoop_{1}", songName, NotesDifficulty.Easy.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_GuitarCoop_{1}", songName, NotesDifficulty.Medium.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_GuitarCoop_{1}", songName, NotesDifficulty.Hard.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_GuitarCoop_{1}", songName, NotesDifficulty.Expert.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_RhythmCoop_{1}", songName, NotesDifficulty.Easy.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_RhythmCoop_{1}", songName, NotesDifficulty.Medium.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_RhythmCoop_{1}", songName, NotesDifficulty.Hard.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Song_RhythmCoop_{1}", songName, NotesDifficulty.Expert.ToString())), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_BossBattleP1", songName)), false);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_BossBattleP2", songName)), false);
clearQbItems(ar);
//start with expert guitar and work down the difficulties to find a GHItem with Face off, copy in to BOss Battle also
if (faceOffItem != null)
{
QbItemArray fo1 = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_FaceOffP1", songName)), false);
QbItemArray fo2 = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_FaceOffP2", songName)), false);
if (faceOffItem.IsMapped && faceOffItem.MappedFileItem != null && faceOffItem.MappedFileItem.FaceOffP1Count + faceOffItem.MappedFileItem.FaceOffP2Count != 0)
{
faceOffP1Ints = adjustFaceOff(faceOffP1Ints);
replaceQbItems(fo1, faceOffP1Ints, true, 2);
//ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_BossBattleP1", songName)), false);
//replaceQbItems(ar, faceOffP1Ints, true, 2);
faceOffP2Ints = adjustFaceOff(faceOffP2Ints);
replaceQbItems(fo2, faceOffP2Ints, true, 2);
//ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_BossBattleP2", songName)), false);
//replaceQbItems(ar, faceOffP2Ints, true, 2);
}
else
{
clearQbItems(fo1);
clearQbItems(fo2);
}
}
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_TimeSig", songName)), false);
replaceQbItems(ar, timeSig, true);
setLength(ar, this.Length, 3, frets, false);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_FretBars", songName)), false);
replaceQbItems(ar, frets, false);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Markers", songName)), false);
if (markers.Length != 0)
setMarkers(frets, ar, qbText, markers);
else
calculateMarkers(frets, ar, qbText);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Scripts_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Anim_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Triggers_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Cameras_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Lightshow_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Crowd_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Drums_Notes", songName)), false);
////setLength(ar, this.Length, 3, frets, true);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Performance_Notes", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Scripts", songName)), false);
if (this.SongQb.IsBoss) //set the death drain marker to the correct location
setDeathDrain(ar, markers);
else
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Anim", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Triggers", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Cameras", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Lightshow", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Crowd", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Drums", songName)), false);
////setLength(ar, this.Length, 3, frets, true);
clearQbItems(ar);
ar = (QbItemArray)qb.FindItem(QbKey.Create(string.Format("{0}_Performance", songName)), false);
setLength(ar, this.Length, 3, frets, true);
//clearQbItems(ar);
qb.AlignPointers();
qb.IsValid();
qbText.AlignPointers();
qbText.IsValid();
long origPakLen = pak.FileLength;
string tmpPak = string.Format("{0}_{1}", notesPak, Guid.NewGuid().ToString("N"));
File.Copy(notesPak, tmpPak);
if (_project.GameInfo.MidTextInQbPak)
{
//save markers to qbPak
_project.FileManager.QbPakEditor.ReplaceFile(_project.GameInfo.GetNotesTextQbFilename(song), qbText);
}
else //save markers to mid pak
{
pak.ReplaceFile(_project.GameInfo.GetNotesTextQbFilename(song), qbText);
}
//replace notes to mid pak
pak.ReplaceFile(_project.GameInfo.GetNotesQbFilename(song), qb);
//pad notes pak with original file
//add padding to ensure song works - This took over a month of testing to find!!
//////////using (FileStream fs = new FileStream(notesPak, FileMode.Open, FileAccess.ReadWrite))
//////////{
////////// using (FileStream fsI = new FileStream(tmpPak, FileMode.Open, FileAccess.Read))
////////// {
////////// fs.Seek(0, SeekOrigin.End);
////////// string tag = " -=> NANOOK <=- PADDING BELOW ";
////////// if (fs.Position + tag.Length < fsI.Length)
////////// fs.Write(Encoding.Default.GetBytes(tag), 0, tag.Length);
////////// if (fs.Position < fsI.Length)
////////// {
////////// fsI.Seek(fs.Position, SeekOrigin.Begin);
////////// copy(fsI, fs, fsI.Length - fsI.Position);
////////// }
////////// }
//////////}
FileHelper.Delete(tmpPak);
return notesLength;
}