Merge branch 'SongLoader' into develop
This commit is contained in:
commit
91afb830b5
37 files changed
+1550
-903
No files matched your search
@@ -504,7 +504,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
CBase.BackgroundMusic.SetStatus(true);
|
||||
|
||||
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.PreviewStart);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.Preview.StartTime);
|
||||
CBase.Sound.SetStreamVolume(_PreviewStream, 0f);
|
||||
CBase.Sound.Play(_PreviewStream);
|
||||
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
|
||||
@@ -528,7 +528,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
CBase.BackgroundMusic.SetStatus(true);
|
||||
|
||||
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.PreviewStart);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.Preview.StartTime);
|
||||
CBase.Sound.SetStreamVolume(_PreviewStream, 0f);
|
||||
CBase.Sound.Play(_PreviewStream);
|
||||
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
|
||||
|
||||
+1
-4
@@ -1,6 +1,6 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Express 2012 for Windows Desktop
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{6F3E1874-F28A-40E9-AFBD-31934D593678} = {6F3E1874-F28A-40E9-AFBD-31934D593678}
|
||||
@@ -154,7 +154,4 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -90,11 +90,6 @@ namespace Vocaluxe.Base
|
||||
get { return _CurrentPlaylistElement.SongID; }
|
||||
}
|
||||
|
||||
public static bool Duet
|
||||
{
|
||||
get { return _CurrentPlaylistElement.Duet; }
|
||||
}
|
||||
|
||||
public static bool SongHasVideo
|
||||
{
|
||||
get { return File.Exists(_CurrentPlaylistElement.VideoFilePath); }
|
||||
@@ -581,17 +576,6 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
}
|
||||
|
||||
public bool Duet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Song != null)
|
||||
return _Song.IsDuet;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public CPlaylistElement(CSong song)
|
||||
{
|
||||
MusicFilePath = string.Empty;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
// Debug
|
||||
public static EDebugLevel DebugLevel = EDebugLevel.TR_CONFIG_OFF;
|
||||
public static EOffOn SaveModifiedSongs = EOffOn.TR_CONFIG_OFF;
|
||||
|
||||
// Graphics
|
||||
#if WIN
|
||||
@@ -169,6 +170,7 @@ namespace Vocaluxe.Base
|
||||
return;
|
||||
|
||||
xmlReader.TryGetEnumValue("//root/Debug/DebugLevel", ref DebugLevel);
|
||||
xmlReader.TryGetEnumValue("//root/Debug/SaveModifiedSongs", ref SaveModifiedSongs);
|
||||
|
||||
#region Graphics
|
||||
xmlReader.TryGetEnumValue("//root/Graphics/Renderer", ref Renderer);
|
||||
@@ -328,6 +330,9 @@ namespace Vocaluxe.Base
|
||||
writer.WriteComment("DebugLevel: " + CHelper.ListStrings(Enum.GetNames(typeof(EDebugLevel))));
|
||||
writer.WriteElementString("DebugLevel", Enum.GetName(typeof(EDebugLevel), DebugLevel));
|
||||
|
||||
writer.WriteComment("SaveModifiedSongs: " + CHelper.ListStrings(Enum.GetNames(typeof(EOffOn))));
|
||||
writer.WriteElementString("SaveModifiedSongs", Enum.GetName(typeof(EOffOn), SaveModifiedSongs));
|
||||
|
||||
writer.WriteEndElement();
|
||||
#endregion Debug
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace Vocaluxe.Base
|
||||
for (int beat = _LastEvalBeat + 1; beat <= RecordedBeat; beat++)
|
||||
{
|
||||
if ((_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_MEDLEY && song.Medley.EndBeat == beat) ||
|
||||
(_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_SHORTSONG && song.ShortEnd == beat))
|
||||
(_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_SHORTSONG && song.ShortEnd.EndBeat == beat))
|
||||
Players[p].SongFinished = true;
|
||||
|
||||
CSongLine[] lines = song.Notes.GetVoice(Players[p].VoiceNr).Lines;
|
||||
@@ -290,7 +290,7 @@ namespace Vocaluxe.Base
|
||||
//CSound.RecordSetTone(p, Tone);
|
||||
double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[note].PointsForBeat /
|
||||
song.Notes.GetVoice(Players[p].VoiceNr).Points;
|
||||
if (notes[note].NoteType == ENoteType.Golden)
|
||||
if (notes[note].Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes += points;
|
||||
|
||||
Players[p].Points += points;
|
||||
@@ -384,7 +384,7 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
if (note.StartBeat < nextStart)
|
||||
{
|
||||
if (note.Hit && note.HitNote.NoteType==ENoteType.Golden)
|
||||
if (note.Hit && note.HitNote.Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes += note.Points;
|
||||
Players[p].Points += note.Points;
|
||||
}
|
||||
@@ -394,7 +394,7 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
while (line.NoteCount > n && n >= 0)
|
||||
{
|
||||
if (line.Notes[n].Hit && line.Notes[n].HitNote.NoteType == ENoteType.Golden)
|
||||
if (line.Notes[n].Hit && line.Notes[n].HitNote.Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes -= line.Notes[n].Points;
|
||||
Players[p].Points -= line.Notes[n].Points;
|
||||
line.DeleteNote(n);
|
||||
@@ -406,9 +406,9 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
Players[p].SungLines.RemoveRange(deleteLine, Players[p].SungLines.Count - deleteLine);
|
||||
}
|
||||
CSong song = GetSong();
|
||||
for (int i = 0; i < GetSong().Notes.Voices[0].Lines.Length; i++)
|
||||
CLog.LogError((i + 1) + ". " + song.Notes.Voices[0].Lines[i].NoteCount + " - " + Players[0].SungLines[i].NoteCount);
|
||||
//CSong song = GetSong();
|
||||
//for (int i = 0; i < GetSong().Notes.Voices[0].Lines.Length; i++)
|
||||
// CLog.LogError((i + 1) + ". " + song.Notes.Voices[0].Lines[i].NoteCount + " - " + Players[0].SungLines[i].NoteCount);
|
||||
|
||||
CSound.SetPosition(soundStream, time);
|
||||
CVideo.Skip(vidStream, time, GetSong().VideoGap);
|
||||
|
||||
@@ -117,8 +117,7 @@ namespace Vocaluxe.Base
|
||||
MessageBox.Show(errorText, CSettings.ProgramName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
if (e != null)
|
||||
errorText += ": " + e;
|
||||
_ErrorLog.Add(_NumErrors + ") " + errorText + "\r\n");
|
||||
_ErrorLog.Add(String.Empty);
|
||||
_ErrorLog.Add(_NumErrors + ") " + errorText);
|
||||
if (exit)
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
|
||||
+11
-1
@@ -60,6 +60,11 @@ namespace Vocaluxe.Base
|
||||
|
||||
class CBconfig : IConfig
|
||||
{
|
||||
public EOffOn GetSaveModifiedSongs()
|
||||
{
|
||||
return CConfig.SaveModifiedSongs;
|
||||
}
|
||||
|
||||
public void SetBackgroundMusicVolume(int newVolume)
|
||||
{
|
||||
CConfig.BackgroundMusicVolume = newVolume;
|
||||
@@ -110,7 +115,7 @@ namespace Vocaluxe.Base
|
||||
return CConfig.CoverSize;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetSongFolder()
|
||||
public IEnumerable<string> GetSongFolders()
|
||||
{
|
||||
return CConfig.SongFolder;
|
||||
}
|
||||
@@ -527,6 +532,11 @@ namespace Vocaluxe.Base
|
||||
return CGame.GetTimeFromBeats(beat, bpm);
|
||||
}
|
||||
|
||||
public float GetBeatFromTime(float time, float bpm, float gap)
|
||||
{
|
||||
return CGame.GetBeatFromTime(time, bpm, gap);
|
||||
}
|
||||
|
||||
public void AddSong(int songID, EGameMode gameMode)
|
||||
{
|
||||
CGame.AddSong(songID, gameMode);
|
||||
|
||||
@@ -157,10 +157,10 @@ namespace Vocaluxe.Base
|
||||
switch (_SongSorting)
|
||||
{
|
||||
case ESongSorting.TR_CONFIG_EDITION:
|
||||
fieldName = "Edition";
|
||||
fieldName = "Editions";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_GENRE:
|
||||
fieldName = "Genre";
|
||||
fieldName = "Genres";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_FOLDER:
|
||||
fieldName = "FolderName";
|
||||
@@ -177,7 +177,7 @@ namespace Vocaluxe.Base
|
||||
fieldName = "Year";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_LANGUAGE:
|
||||
fieldName = "Language";
|
||||
fieldName = "Languages";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_DATEADDED:
|
||||
fieldName = "DateAdded";
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace Vocaluxe.Base
|
||||
if (song == null)
|
||||
continue;
|
||||
song.ID = _Songs.Count;
|
||||
if (song.ReadNotes())
|
||||
if (song.LoadNotes())
|
||||
_Songs.Add(song);
|
||||
}
|
||||
CLog.StopBenchmark(2, "Read TXTs");
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
return song;
|
||||
return (song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_NORMAL)) ? song : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
return (song.IsDuet) ? song : null;
|
||||
return (song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET)) ? song : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,11 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
var newSong = new CSong(song) {Finish = CGame.GetTimeFromBeats(song.ShortEnd, song.BPM) + CSettings.DefaultMedleyFadeOutTime + song.Gap};
|
||||
if (!song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_SHORTSONG))
|
||||
return null;
|
||||
var newSong = new CSong(song) {Finish = CGame.GetTimeFromBeats(song.ShortEnd.EndBeat, song.BPM) + CSettings.DefaultMedleyFadeOutTime + song.Gap};
|
||||
// set lines to short mode
|
||||
newSong.Notes.SetMedley(song.Notes.GetVoice(0).Lines[0].FirstNoteBeat, song.ShortEnd);
|
||||
newSong.Notes.SetMedley(0, song.ShortEnd.EndBeat);
|
||||
|
||||
return newSong;
|
||||
}
|
||||
@@ -80,6 +82,8 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
if (!song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
return null;
|
||||
var newSong = new CSong(song) {Start = CGame.GetTimeFromBeats(song.Medley.StartBeat, song.BPM) - song.Medley.FadeInTime + song.Gap};
|
||||
if (newSong.Start < 0f)
|
||||
newSong.Start = 0f;
|
||||
|
||||
@@ -180,7 +180,11 @@ namespace Vocaluxe.Lib.Playlist
|
||||
|
||||
public void AddSong(int songID)
|
||||
{
|
||||
var song = new CPlaylistSong {SongID = songID, GameMode = CSongs.GetSong(songID).IsDuet ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL};
|
||||
var song = new CPlaylistSong
|
||||
{
|
||||
SongID = songID,
|
||||
GameMode = CSongs.GetSong(songID).IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET) ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL
|
||||
};
|
||||
|
||||
Songs.Add(song);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ namespace Vocaluxe.Screens
|
||||
CGame.ClearSongs();
|
||||
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
if (CSongs.AllSongs[songNr].IsDuet)
|
||||
if (CSongs.AllSongs[songNr].IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET))
|
||||
gm = EGameMode.TR_GAMEMODE_DUET;
|
||||
|
||||
CGame.AddSong(songNr, gm);
|
||||
|
||||
@@ -22,6 +22,7 @@ using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
namespace Vocaluxe.Screens
|
||||
{
|
||||
@@ -597,6 +598,8 @@ namespace Vocaluxe.Screens
|
||||
_CheckMics();
|
||||
_CheckPlayers();
|
||||
|
||||
CSong firstSong = CGame.GetSong(0);
|
||||
|
||||
for (int i = 0; i < CSettings.MaxNumPlayer; i++)
|
||||
{
|
||||
_Statics[_StaticPlayerAvatar[i]].Texture = CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID) ?
|
||||
@@ -607,8 +610,9 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Clear();
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Visible = i + 1 <= CGame.NumPlayer;
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(1).DuetPart1);
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(1).DuetPart2);
|
||||
|
||||
for (int j = 0; j < firstSong.Notes.VoiceCount; j++)
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(firstSong.Notes.VoiceNames[j]);
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Selection = i % 2;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -297,10 +297,8 @@ namespace Vocaluxe.Screens
|
||||
string name = CProfiles.GetPlayerName(players[p].ProfileID, p);
|
||||
if (song != null && song.IsDuet)
|
||||
{
|
||||
if (players[p].VoiceNr == 0 && song.DuetPart1 != "Part 1")
|
||||
name += " (" + song.DuetPart1 + ")";
|
||||
else if (players[p].VoiceNr == 1 && song.DuetPart2 != "Part 2")
|
||||
name += " (" + song.DuetPart2 + ")";
|
||||
if (song.Notes.VoiceNames.IsSet(players[p].VoiceNr))
|
||||
name += " (" + song.Notes.VoiceNames[players[p].VoiceNr] + ")";
|
||||
}
|
||||
_Texts[_TextNames[p, CGame.NumPlayer - 1]].Text = name;
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ namespace Vocaluxe.Screens
|
||||
_LoadNextSong();
|
||||
|
||||
_UpdateSongText();
|
||||
_UpdateDuetText();
|
||||
_UpdateDuetNames();
|
||||
if (_FadeOut)
|
||||
return true;
|
||||
|
||||
@@ -387,12 +387,8 @@ namespace Vocaluxe.Screens
|
||||
|
||||
for (int p = 0; p < CGame.NumPlayer; p++)
|
||||
{
|
||||
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
|
||||
if (CGame.Players[p].Points < 10000)
|
||||
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString("0000");
|
||||
else
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString("00000");
|
||||
string fmtString = (CGame.Players[p].Points < 10000) ? "0000" : "00000";
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString(fmtString);
|
||||
}
|
||||
|
||||
if (_CurrentVideo != -1 && !_FadeOut && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON)
|
||||
@@ -607,12 +603,12 @@ namespace Vocaluxe.Screens
|
||||
_FinishTime = song.Finish;
|
||||
_TimeToFirstNote = 0f;
|
||||
_TimeToFirstNoteDuet = 0f;
|
||||
var duetPlayer = new int[CGame.NumPlayer];
|
||||
var voiceAssignments = new int[CGame.NumPlayer];
|
||||
if (song.IsDuet)
|
||||
{
|
||||
//Save duet-assignment before resetting
|
||||
for (int i = 0; i < duetPlayer.Length; i++)
|
||||
duetPlayer[i] = CGame.Players[i].VoiceNr;
|
||||
for (int i = 0; i < voiceAssignments.Length; i++)
|
||||
voiceAssignments[i] = CGame.Players[i].VoiceNr;
|
||||
}
|
||||
CGame.ResetPlayer();
|
||||
|
||||
@@ -634,8 +630,9 @@ namespace Vocaluxe.Screens
|
||||
|
||||
if (song.IsDuet)
|
||||
{
|
||||
_Texts[_TextDuetName1].Text = song.DuetPart1;
|
||||
_Texts[_TextDuetName2].Text = song.DuetPart2;
|
||||
//TODO: Show more than 2 voicenames
|
||||
_Texts[_TextDuetName1].Text = song.Notes.VoiceNames[0];
|
||||
_Texts[_TextDuetName2].Text = song.Notes.VoiceNames[1];
|
||||
//More than one song: Player is not assigned to line by user
|
||||
//Otherwise, this is done by CScreenNames
|
||||
if (CGame.GetNumSongs() > 1)
|
||||
@@ -646,7 +643,7 @@ namespace Vocaluxe.Screens
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < CGame.NumPlayer; i++)
|
||||
CGame.Players[i].VoiceNr = duetPlayer[i];
|
||||
CGame.Players[i].VoiceNr = voiceAssignments[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,14 +669,11 @@ namespace Vocaluxe.Screens
|
||||
NoteLines[3] = SingNotes[SingBars].AddPlayer(new SRectF(640f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[3]);
|
||||
break;
|
||||
*/
|
||||
_TimerSongText.Stop();
|
||||
_TimerSongText.Reset();
|
||||
_TimerDuetText1.Stop();
|
||||
_TimerDuetText1.Reset();
|
||||
_TimerDuetText2.Stop();
|
||||
_TimerDuetText2.Reset();
|
||||
|
||||
if (song.Notes.Voices.Length != 2)
|
||||
if (!song.IsDuet)
|
||||
_TimerSongText.Start();
|
||||
|
||||
_StartSong();
|
||||
@@ -781,7 +775,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
|
||||
_CurrentBeat = CGame.CurrentBeat;
|
||||
for (int i = 0; i < song.Notes.LinesCount; i++)
|
||||
for (int i = 0; i < song.Notes.VoiceCount; i++)
|
||||
{
|
||||
if (i > 1)
|
||||
break; // for later
|
||||
@@ -1090,10 +1084,10 @@ namespace Vocaluxe.Screens
|
||||
if (song == null || !song.NotesLoaded)
|
||||
return null;
|
||||
|
||||
var alpha = new float[song.Notes.Voices.Length * 2];
|
||||
var alpha = new float[song.Notes.VoiceCount * 2];
|
||||
float currentTime = _CurrentTime - song.Gap;
|
||||
|
||||
for (int i = 0; i < song.Notes.LinesCount; i++)
|
||||
for (int i = 0; i < song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = song.Notes.GetVoice(i);
|
||||
CSongLine[] lines = voice.Lines;
|
||||
@@ -1197,8 +1191,8 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
else
|
||||
{
|
||||
_Statics[_StaticSongText].Color.A = (3f - (t - 7f)) / 3f;
|
||||
_Texts[_TextSongName].Color.A = (3f - (t - 7f)) / 3f;
|
||||
_Statics[_StaticSongText].Color.A = 10f - t / 3f;
|
||||
_Texts[_TextSongName].Color.A = 10f - t / 3f;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1215,61 +1209,65 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
}
|
||||
|
||||
private void _UpdateDuetText()
|
||||
private void _UpdateDuetNames(CText textName, Stopwatch timer)
|
||||
{
|
||||
if (CGame.GetSong() != null)
|
||||
if (timer.IsRunning)
|
||||
{
|
||||
//Timer for first duet-part
|
||||
if (_TimerDuetText1.IsRunning)
|
||||
float t = timer.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
float t = _TimerDuetText1.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName1].Visible = true;
|
||||
textName.Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName1].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName1].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName1].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
if (t < 3f)
|
||||
textName.Color.A = t / 3f;
|
||||
else if (t < 7f)
|
||||
textName.Color.A = 1f;
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName1].Visible = false;
|
||||
_TimerDuetText1.Stop();
|
||||
}
|
||||
textName.Color.A = (10f - t) / 3f;
|
||||
}
|
||||
else if (!_TimerDuetText1.IsRunning && _TimerDuetText1.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText1.Start();
|
||||
else
|
||||
_Texts[_TextDuetName1].Visible = false;
|
||||
//Timer for second duet-part
|
||||
if (_TimerDuetText2.IsRunning)
|
||||
{
|
||||
float t = _TimerDuetText2.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName2].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
_TimerDuetText2.Stop();
|
||||
}
|
||||
textName.Visible = false;
|
||||
timer.Stop();
|
||||
}
|
||||
else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText2.Start();
|
||||
else
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
}
|
||||
else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
timer.Start();
|
||||
else
|
||||
textName.Visible = false;
|
||||
}
|
||||
|
||||
private void _UpdateDuetNames()
|
||||
{
|
||||
if (CGame.GetSong() == null)
|
||||
return;
|
||||
//Timer for first duet-part
|
||||
_UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1);
|
||||
//Timer for second duet-part
|
||||
if (_TimerDuetText2.IsRunning)
|
||||
{
|
||||
float t = _TimerDuetText2.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName2].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
_TimerDuetText2.Stop();
|
||||
}
|
||||
}
|
||||
else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText2.Start();
|
||||
else
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
}
|
||||
|
||||
private void _UpdateTimeLine()
|
||||
|
||||
@@ -819,9 +819,8 @@ namespace Vocaluxe.Screens
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
|
||||
CGame.AddVisibleSong(songNr, gm);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, gm))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,9 +833,8 @@ namespace Vocaluxe.Screens
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
|
||||
CGame.AddVisibleSong(songNr, gm);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, gm))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,14 +842,13 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
if ((CSongs.Category >= 0) && (songNr >= 0))
|
||||
{
|
||||
if (CSongs.VisibleSongs[songNr].Medley.Source == EMedleySource.None)
|
||||
if (!CSongs.VisibleSongs[songNr].IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
return;
|
||||
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,6 +1162,15 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
}
|
||||
|
||||
private void _CheckAndAddGameMode(EGameMode gameMode)
|
||||
{
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].IsGameModeAvailable(gameMode))
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), gameMode));
|
||||
_AvailableGameModes.Add(gameMode);
|
||||
}
|
||||
}
|
||||
|
||||
private void _ShowSongOptionsSong()
|
||||
{
|
||||
var lastMode = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
@@ -1172,23 +1178,11 @@ namespace Vocaluxe.Screens
|
||||
lastMode = _AvailableGameModes[_SelectSlides[_SelectSlideOptionsMode].Selection];
|
||||
_AvailableGameModes.Clear();
|
||||
_SelectSlides[_SelectSlideOptionsMode].Clear();
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].IsDuet)
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_DUET));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_DUET);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_NORMAL));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_NORMAL);
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_SHORTSONG));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
}
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].Medley.Source != EMedleySource.None)
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_MEDLEY));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
}
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_NORMAL);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_DUET);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
|
||||
//Set SelectSlide-Selection to last selected game-mode if possible
|
||||
for (int i = 0; i < _AvailableGameModes.Count; i++)
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Vocaluxe.SongQueue
|
||||
|
||||
private bool _AddSong(int songID, EGameMode gameMode)
|
||||
{
|
||||
if (gameMode == EGameMode.TR_GAMEMODE_DUET && !CSongs.GetSong(songID).IsDuet)
|
||||
if (!CSongs.GetSong(songID).IsGameModeAvailable(gameMode))
|
||||
return false;
|
||||
|
||||
_SongQueue.Add(new SSongQueueEntry(songID, gameMode));
|
||||
|
||||
+4
-11
@@ -53,7 +53,6 @@ namespace VocaluxeLib
|
||||
public static string ListStrings(string[] str)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
result += str[i];
|
||||
@@ -160,13 +159,7 @@ namespace VocaluxeLib
|
||||
return files;
|
||||
}
|
||||
|
||||
public static bool TryParse<T>(string value, out T result)
|
||||
where T : struct
|
||||
{
|
||||
return TryParse(value, out result, false);
|
||||
}
|
||||
|
||||
public static bool TryParse<T>(string value, out T result, bool ignoreCase)
|
||||
public static bool TryParse<T>(string value, out T result, bool ignoreCase=false)
|
||||
where T : struct
|
||||
{
|
||||
result = default(T);
|
||||
@@ -199,7 +192,7 @@ namespace VocaluxeLib
|
||||
|
||||
static class CEncoding
|
||||
{
|
||||
public static Encoding GetEncoding(string encodingName)
|
||||
public static Encoding GetEncoding(this string encodingName)
|
||||
{
|
||||
switch (encodingName)
|
||||
{
|
||||
@@ -214,11 +207,11 @@ namespace VocaluxeLib
|
||||
case "UTF8":
|
||||
return Encoding.UTF8;
|
||||
default:
|
||||
return Encoding.UTF8;
|
||||
return Encoding.Default;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetEncodingName(Encoding enc)
|
||||
public static string GetEncodingName(this Encoding enc)
|
||||
{
|
||||
string result = "UTF8";
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace VocaluxeLib
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resizes the given list to the given size. Removes elements or adds default values
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public static void Resize<T>(this List<T> list, int size, T defaultValue = default(T))
|
||||
{
|
||||
int curSize = list.Count;
|
||||
if (size < curSize)
|
||||
list.RemoveRange(size, curSize - size);
|
||||
else if (size > curSize)
|
||||
list.AddRange(Enumerable.Repeat(defaultValue, size - curSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the list at least the given size adding the given default values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public static void EnsureSize<T>(this List<T> list, int size, T defaultValue)
|
||||
{
|
||||
int curSize = list.Count;
|
||||
if (size > curSize)
|
||||
list.AddRange(Enumerable.Repeat(defaultValue, size - curSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the list at least the given size adding a new instance of T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
public static void EnsureSize<T>(this List<T> list, int size) where T : new()
|
||||
{
|
||||
if (size > list.Count)
|
||||
list.Add(new T());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all set bits starting from lowest (Bit 0)
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<int> GetSetBits(this int value)
|
||||
{
|
||||
var result = new List<int>();
|
||||
int curBit = 0;
|
||||
//Evaluate as bitset
|
||||
while (value > 0)
|
||||
{
|
||||
if ((value & 1) != 0)
|
||||
result.Add(curBit);
|
||||
value >>= 1;
|
||||
curBit++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool ContainsIgnoreCase(this string value, string other)
|
||||
{
|
||||
return value.IndexOf(other, StringComparison.CurrentCultureIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
public static string TrimMultipleWs(this string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
int start = 0;
|
||||
int len = value.Length;
|
||||
while (value[start] == ' ')
|
||||
{
|
||||
start++;
|
||||
if (start >= len)
|
||||
return "";
|
||||
}
|
||||
if (start > 0)
|
||||
start--;
|
||||
int end = --len;
|
||||
while (value[end] == ' ')
|
||||
end--;
|
||||
if (end < len)
|
||||
end++;
|
||||
if (end - start < len)
|
||||
value = value.Substring(start, end - start + 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts value to a string in fixed point notation using invariant formating (english style decimal point)
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be converted</param>
|
||||
/// <returns>String representation of value</returns>
|
||||
public static string ToInvariantString(this float value)
|
||||
{
|
||||
return value.ToString("F", NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ namespace VocaluxeLib
|
||||
{
|
||||
public interface IConfig
|
||||
{
|
||||
EOffOn GetSaveModifiedSongs();
|
||||
|
||||
void SetBackgroundMusicVolume(int newVolume);
|
||||
int GetBackgroundMusicVolume();
|
||||
|
||||
@@ -45,7 +47,7 @@ namespace VocaluxeLib
|
||||
|
||||
int GetCoverSize();
|
||||
|
||||
IEnumerable<string> GetSongFolder();
|
||||
IEnumerable<string> GetSongFolders();
|
||||
ESongSorting GetSongSorting();
|
||||
EOffOn GetTabs();
|
||||
EOffOn GetIgnoreArticles();
|
||||
@@ -179,6 +181,7 @@ namespace VocaluxeLib
|
||||
double GetRandomDouble();
|
||||
|
||||
float GetTimeFromBeats(float beat, float bpm);
|
||||
float GetBeatFromTime(float time, float bpm, float gap);
|
||||
|
||||
void AddSong(int songID, EGameMode gameMode);
|
||||
void Reset();
|
||||
|
||||
+55
-108
@@ -23,15 +23,6 @@ using VocaluxeLib.Songs;
|
||||
|
||||
namespace VocaluxeLib.Menu
|
||||
{
|
||||
struct SNote
|
||||
{
|
||||
public string Text;
|
||||
public int StartBeat;
|
||||
public int EndBeat;
|
||||
public int Duration;
|
||||
public ENoteType Type;
|
||||
}
|
||||
|
||||
struct SThemeLyrics
|
||||
{
|
||||
public string Name;
|
||||
@@ -46,7 +37,10 @@ namespace VocaluxeLib.Menu
|
||||
private SThemeLyrics _Theme;
|
||||
private bool _ThemeLoaded;
|
||||
|
||||
private readonly List<SNote> _Notes;
|
||||
/// <summary>
|
||||
/// Holds a reference to Songline. DO NOT MODIFY
|
||||
/// </summary>
|
||||
private CSongLine _Line;
|
||||
private CText _Text;
|
||||
|
||||
private float _X;
|
||||
@@ -109,7 +103,7 @@ namespace VocaluxeLib.Menu
|
||||
_MaxW = 1f;
|
||||
_H = 1f;
|
||||
_Width = 1f;
|
||||
_Notes = new List<SNote>();
|
||||
_Line = new CSongLine();
|
||||
_Text = new CText(_PartyModeID);
|
||||
|
||||
LyricStyle = ELyricStyle.Fill;
|
||||
@@ -201,28 +195,27 @@ namespace VocaluxeLib.Menu
|
||||
|
||||
public void SetLine(CSongLine line)
|
||||
{
|
||||
_Notes.Clear();
|
||||
|
||||
_Line = line;
|
||||
_Width = 0f;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
var n = new SNote {Text = note.Text, StartBeat = note.StartBeat, EndBeat = note.EndBeat, Duration = note.Duration, Type = note.NoteType};
|
||||
|
||||
_Text.Text = note.Text;
|
||||
_Text.Style = EStyle.Bold;
|
||||
|
||||
if (n.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_Width += rect.Width;
|
||||
_Notes.Add(n);
|
||||
_SetText(note);
|
||||
_Width += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
private void _SetText(CSongNote note)
|
||||
{
|
||||
_Text.Text = note.Text;
|
||||
_Text.Style = EStyle.Bold;
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_Notes.Clear();
|
||||
_Line = new CSongLine();
|
||||
}
|
||||
|
||||
public float GetCurrentLyricPosX()
|
||||
@@ -260,15 +253,10 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
float x = _X - _Width / 2;
|
||||
|
||||
foreach (SNote note in _Notes)
|
||||
foreach (CSongNote note in _Line.Notes)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = note.Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
_SetText(note);
|
||||
|
||||
if (currentBeat >= note.StartBeat)
|
||||
{
|
||||
@@ -276,9 +264,8 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
_Text.Color = _ColorProcessed;
|
||||
|
||||
|
||||
float diff = note.EndBeat - note.StartBeat;
|
||||
if (Math.Abs(diff) < float.Epsilon)
|
||||
int diff = note.EndBeat - note.StartBeat;
|
||||
if (diff <= 0)
|
||||
_Text.Draw(0f, 1f);
|
||||
else
|
||||
{
|
||||
@@ -299,7 +286,7 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,37 +295,27 @@ namespace VocaluxeLib.Menu
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
//find last active note
|
||||
int lastNote = -1;
|
||||
for (int i = 0; i < _Notes.Count; i++)
|
||||
{
|
||||
if (currentBeat >= _Notes[i].StartBeat)
|
||||
lastNote = i;
|
||||
}
|
||||
int lastNote = _Line.FindPreviousNote((int)currentBeat);
|
||||
|
||||
int zoomNote = -1;
|
||||
int endBeat = -1;
|
||||
float zoomx = 0f;
|
||||
|
||||
for (int note = 0; note < _Notes.Count; note++)
|
||||
for (int note = 0; note < _Line.Notes.Length; note++)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = _Notes[note].Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_SetText(_Line.Notes[note]);
|
||||
|
||||
if (_Notes[note].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
if (currentBeat >= _Notes[note].StartBeat)
|
||||
if (currentBeat >= _Line.Notes[note].StartBeat)
|
||||
{
|
||||
int endbeat = _Notes[note].EndBeat;
|
||||
if (note < _Notes.Count - 1)
|
||||
endbeat = _Notes[note + 1].StartBeat - 1;
|
||||
int curEndBeat = _Line.Notes[note].EndBeat;
|
||||
if (note < _Line.Notes.Length - 1)
|
||||
curEndBeat = _Line.Notes[note + 1].StartBeat - 1;
|
||||
|
||||
if (currentBeat <= endbeat)
|
||||
if (currentBeat <= curEndBeat)
|
||||
{
|
||||
zoomNote = note;
|
||||
endBeat = endbeat;
|
||||
endBeat = curEndBeat;
|
||||
zoomx = _Text.X;
|
||||
}
|
||||
else
|
||||
@@ -356,49 +333,37 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
|
||||
if (zoomNote > -1)
|
||||
{
|
||||
if (_Notes[zoomNote].Duration == 0)
|
||||
return;
|
||||
|
||||
_Text.X = zoomx;
|
||||
_Text.Text = _Notes[zoomNote].Text;
|
||||
_Text.Color = _ColorProcessed;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_SetText(_Line.Notes[zoomNote]);
|
||||
|
||||
if (_Notes[zoomNote].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
float diff = endBeat - _Notes[zoomNote].StartBeat;
|
||||
float diff = endBeat - _Line.Notes[zoomNote].StartBeat;
|
||||
if (diff <= 0f)
|
||||
diff = 1f;
|
||||
|
||||
float p = (currentBeat - _Notes[zoomNote].StartBeat) / diff;
|
||||
float p = (currentBeat - _Line.Notes[zoomNote].StartBeat) / diff;
|
||||
if (p > 1f)
|
||||
p = 1f;
|
||||
|
||||
p = 1f - p;
|
||||
|
||||
float ty = _Text.Y;
|
||||
float tx = _Text.X;
|
||||
float th = _Text.Height;
|
||||
float tz = _Text.Z;
|
||||
|
||||
SRectF normalRect = _Text.Rect;
|
||||
_Text.Height += _Text.Height * p * 0.4f;
|
||||
RectangleF rectz = CBase.Fonts.GetTextBounds(_Text);
|
||||
_Text.X -= (rectz.Width - rect.Width) / 2f;
|
||||
_Text.Y -= (rectz.Height - rect.Height) / 2f;
|
||||
_Text.X -= (_Text.Rect.W - normalRect.W) / 2f;
|
||||
_Text.Y -= (_Text.Rect.W - normalRect.H) / 2f;
|
||||
_Text.Z -= 0.1f;
|
||||
|
||||
_Text.Draw();
|
||||
|
||||
_Text.Y = ty;
|
||||
_Text.X = tx;
|
||||
_Text.Height = th;
|
||||
_Text.Z = tz;
|
||||
}
|
||||
@@ -408,15 +373,10 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
foreach (SNote note in _Notes)
|
||||
foreach (CSongNote note in _Line.Notes)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = note.Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
_SetText(note);
|
||||
|
||||
if (currentBeat >= note.StartBeat)
|
||||
{
|
||||
@@ -430,7 +390,7 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,29 +399,23 @@ namespace VocaluxeLib.Menu
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
//find last active note
|
||||
int lastNote = -1;
|
||||
for (int i = 0; i < _Notes.Count; i++)
|
||||
{
|
||||
if (currentBeat >= _Notes[i].StartBeat)
|
||||
lastNote = i;
|
||||
}
|
||||
int lastNote = _Line.FindPreviousNote((int)currentBeat);
|
||||
|
||||
int jumpNote = -1;
|
||||
float jumpx = 0f;
|
||||
|
||||
for (int note = 0; note < _Notes.Count; note++)
|
||||
for (int note = 0; note < _Line.Notes.Length; note++)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = _Notes[note].Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_SetText(_Line.Notes[note]);
|
||||
|
||||
if (_Notes[note].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
if (currentBeat >= _Notes[note].StartBeat)
|
||||
if (currentBeat >= _Line.Notes[note].StartBeat)
|
||||
{
|
||||
if (currentBeat <= _Notes[note].EndBeat)
|
||||
int curEndBeat = _Line.Notes[note].EndBeat;
|
||||
if (note < _Line.Notes.Length - 1)
|
||||
curEndBeat = _Line.Notes[note + 1].StartBeat - 1;
|
||||
|
||||
if (currentBeat <= curEndBeat)
|
||||
{
|
||||
jumpNote = note;
|
||||
jumpx = _Text.X;
|
||||
@@ -481,27 +435,20 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
|
||||
if (jumpNote < 0)
|
||||
return;
|
||||
if (_Notes[jumpNote].Duration == 0)
|
||||
return;
|
||||
|
||||
_Text.X = jumpx;
|
||||
_Text.Text = _Notes[jumpNote].Text;
|
||||
_Text.Color = _ColorProcessed;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_SetText(_Line.Notes[jumpNote]);
|
||||
|
||||
if (_Notes[jumpNote].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
int diff = _Notes[jumpNote].EndBeat - _Notes[jumpNote].StartBeat;
|
||||
int diff = _Line.Notes[jumpNote].EndBeat - _Line.Notes[jumpNote].StartBeat;
|
||||
if (diff <= 0)
|
||||
diff = 1;
|
||||
|
||||
float p = 1f - (currentBeat - _Notes[jumpNote].StartBeat) / diff;
|
||||
float p = 1f - (currentBeat - _Line.Notes[jumpNote].StartBeat) / diff;
|
||||
|
||||
if (Math.Abs(p) < float.Epsilon)
|
||||
_Text.Draw();
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
private class CPlaylistElementContent
|
||||
{
|
||||
public EGameMode[] Modes;
|
||||
public IList<EGameMode> Modes;
|
||||
public int SongID;
|
||||
public EGameMode Mode;
|
||||
}
|
||||
@@ -971,11 +971,11 @@ namespace VocaluxeLib.Menu
|
||||
|
||||
if (!mouseEvent.LBH && DragAndDropSongID != -1)
|
||||
{
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
CSong song = CBase.Songs.GetSongByID(DragAndDropSongID);
|
||||
|
||||
if (song != null)
|
||||
{
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
if (song.IsDuet)
|
||||
gm = EGameMode.TR_GAMEMODE_DUET;
|
||||
|
||||
@@ -1220,7 +1220,7 @@ namespace VocaluxeLib.Menu
|
||||
string t1 = CBase.Language.Translate(_Theme.Text1.Text).Replace("%a", song.Artist).Replace("%t", song.Title);
|
||||
_PlaylistElements[i].Text1.Text = /*(Offset + i + 1) + ") " + */ t1; //TODO: Add text field for the number
|
||||
_PlaylistElements[i].SelectSlide.Clear();
|
||||
for (int g = 0; g < pec.Modes.Length; g++)
|
||||
for (int g = 0; g < pec.Modes.Count; g++)
|
||||
{
|
||||
_PlaylistElements[i].SelectSlide.AddValue(Enum.GetName(typeof(EGameMode), pec.Modes[g]));
|
||||
if (pec.Modes[g] == pec.Mode)
|
||||
|
||||
@@ -561,7 +561,7 @@ namespace VocaluxeLib.Menu
|
||||
float y = Y;
|
||||
RectangleF bounds = CBase.Fonts.GetTextBounds(this);
|
||||
|
||||
if (bounds.Width > MaxWidth && MaxWidth > 0f && bounds.Width > 0f)
|
||||
if (MaxWidth > 0f && bounds.Width > MaxWidth && bounds.Width > 0f)
|
||||
{
|
||||
float factor = MaxWidth / bounds.Width;
|
||||
float step = h * (1 - factor);
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
int nr = 1;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
if (note.NoteType != ENoteType.Freestyle)
|
||||
if (note.Type != ENoteType.Freestyle)
|
||||
{
|
||||
float width = note.Duration / beats * w;
|
||||
|
||||
@@ -334,7 +334,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
_DrawNoteBG(rect, color, 1f, _PlayerNotes[n].Timer);
|
||||
_DrawNote(rect, new SColorF(5f, 5f, 5f, 0.7f * _PlayerNotes[n].Alpha), 0.7f);
|
||||
|
||||
if (note.NoteType == ENoteType.Golden)
|
||||
if (note.Type == ENoteType.Golden)
|
||||
{
|
||||
_AddGoldenNote(rect, n, nr);
|
||||
nr++;
|
||||
@@ -386,7 +386,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
|
||||
_DrawNote(rect, color, f);
|
||||
|
||||
if (note.EndBeat >= CBase.Game.GetRecordedBeat() && note.Hit && note.HitNote.NoteType == ENoteType.Golden)
|
||||
if (note.EndBeat >= CBase.Game.GetRecordedBeat() && note.Hit && note.HitNote.Type == ENoteType.Golden)
|
||||
{
|
||||
var re = new SRectF(rect) {W = (CBase.Game.GetMidRecordedBeat() - note.StartBeat) / beats * w};
|
||||
_AddFlare(re, n);
|
||||
|
||||
@@ -22,6 +22,7 @@ using System.IO;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.PartyModes;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
@@ -101,7 +102,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
private readonly Stopwatch _VideoFadeTimer = new Stopwatch();
|
||||
private readonly List<int> _Streams = new List<int>();
|
||||
private int _Actsong = -1;
|
||||
private int _ActSongId = -1;
|
||||
private int _Actsongstream = -1;
|
||||
protected CTexture _Vidtex;
|
||||
|
||||
@@ -186,7 +187,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
protected int _ActSong
|
||||
{
|
||||
get { return _Actsong; }
|
||||
get { return _ActSongId; }
|
||||
}
|
||||
|
||||
public SRectF Rect
|
||||
@@ -206,7 +207,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public virtual int GetActualSelection()
|
||||
{
|
||||
return _Actsong;
|
||||
return _ActSongId;
|
||||
}
|
||||
|
||||
private bool _Selected;
|
||||
@@ -434,7 +435,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if (!_Initialized)
|
||||
return;
|
||||
|
||||
if (_Actsong != _PreviewSelected)
|
||||
if (_ActSongId != _PreviewSelected)
|
||||
_SelectSong(_PreviewSelected);
|
||||
|
||||
if (_Streams.Count <= 0 || _Video == -1)
|
||||
@@ -607,7 +608,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
protected void _SelectSong(int nr)
|
||||
{
|
||||
if (CBase.Songs.IsInCategory() && (CBase.Songs.GetNumSongsVisible() > 0) && (nr >= 0) && ((_Actsong != nr) || (_Streams.Count == 0)))
|
||||
if (CBase.Songs.IsInCategory() && (CBase.Songs.GetNumSongsVisible() > 0) && (nr >= 0) && ((_ActSongId != nr) || (_Streams.Count == 0)))
|
||||
{
|
||||
_Streams.ForEach(soundStream => CBase.Sound.FadeAndStop(soundStream, 0f, 1f));
|
||||
_Streams.Clear();
|
||||
@@ -617,18 +618,19 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
CBase.Drawing.RemoveTexture(ref _Vidtex);
|
||||
|
||||
_Actsong = nr;
|
||||
if (_Actsong >= CBase.Songs.GetNumSongsVisible())
|
||||
_Actsong = 0;
|
||||
_ActSongId = nr;
|
||||
if (_ActSongId >= CBase.Songs.GetNumSongsVisible())
|
||||
_ActSongId = 0;
|
||||
|
||||
|
||||
int stream = CBase.Sound.Load(Path.Combine(CBase.Songs.GetVisibleSong(_Actsong).Folder, CBase.Songs.GetVisibleSong(_Actsong).MP3FileName), true);
|
||||
CSong actSong = CBase.Songs.GetVisibleSong(_ActSongId);
|
||||
int stream = CBase.Sound.Load(Path.Combine(actSong.Folder, actSong.MP3FileName), true);
|
||||
CBase.Sound.SetStreamVolumeMax(stream, _MaxVolume);
|
||||
CBase.Sound.SetStreamVolume(stream, 0f);
|
||||
|
||||
float startposition = CBase.Songs.GetVisibleSong(_Actsong).PreviewStart;
|
||||
float startposition = actSong.Preview.StartTime;
|
||||
|
||||
if (Math.Abs(startposition) < 0.001)
|
||||
if (actSong.Preview.Source == EDataSource.None)
|
||||
startposition = CBase.Sound.GetLength(stream) / 4f;
|
||||
|
||||
if (startposition >= 0.5f)
|
||||
@@ -640,12 +642,12 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
_Streams.Add(stream);
|
||||
_Actsongstream = stream;
|
||||
|
||||
if (CBase.Songs.GetVisibleSong(_Actsong).VideoFileName != "" && CBase.Config.GetVideoPreview() == EOffOn.TR_CONFIG_ON)
|
||||
if (actSong.VideoFileName != "" && CBase.Config.GetVideoPreview() == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
_Video = CBase.Video.Load(Path.Combine(CBase.Songs.GetVisibleSong(_Actsong).Folder, CBase.Songs.GetVisibleSong(_Actsong).VideoFileName));
|
||||
_Video = CBase.Video.Load(Path.Combine(actSong.Folder, actSong.VideoFileName));
|
||||
if (_Video == -1)
|
||||
return;
|
||||
CBase.Video.Skip(_Video, startposition, CBase.Songs.GetVisibleSong(_Actsong).VideoGap);
|
||||
CBase.Video.Skip(_Video, startposition, actSong.VideoGap);
|
||||
_VideoFadeTimer.Stop();
|
||||
_VideoFadeTimer.Reset();
|
||||
_VideoFadeTimer.Start();
|
||||
|
||||
@@ -413,8 +413,8 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
_Title.Text = song.Title;
|
||||
_DuetIcon.Visible = song.IsDuet;
|
||||
_VideoIcon.Visible = song.VideoFileName != "";
|
||||
_MedleyCalcIcon.Visible = song.Medley.Source == EMedleySource.Calculated;
|
||||
_MedleyTagIcon.Visible = song.Medley.Source == EMedleySource.Tag;
|
||||
_MedleyCalcIcon.Visible = song.Medley.Source == EDataSource.Calculated;
|
||||
_MedleyTagIcon.Visible = song.Medley.Source == EDataSource.Tag;
|
||||
|
||||
float time = CBase.Sound.GetLength(_SongStream);
|
||||
if (Math.Abs(song.Finish) > 0.001)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
/// <summary>
|
||||
@@ -38,12 +40,17 @@ namespace VocaluxeLib.Songs
|
||||
StartBeat = startBeat;
|
||||
Duration = duration;
|
||||
Tone = tone;
|
||||
if (Duration < 1)
|
||||
throw new Exception("Note to short. All notes should be at least 1 beat long!");
|
||||
}
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
public int StartBeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Last beat of this note. First valid beat for a note after that is at EndBeat+1
|
||||
/// </summary>
|
||||
public int EndBeat
|
||||
{
|
||||
get { return StartBeat + _Duration - 1; }
|
||||
|
||||
@@ -79,7 +79,11 @@ namespace VocaluxeLib.Songs
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
//Find last note with StartBeat<=Beat
|
||||
/// <summary>
|
||||
/// Find last note with StartBeat<=Beat
|
||||
/// </summary>
|
||||
/// <param name="beat"></param>
|
||||
/// <returns>Note index of last note with StartBeat<=Beat or -1 if all notes start after beat</returns>
|
||||
public int FindPreviousNote(int beat)
|
||||
{
|
||||
//If no notes -> No previous note
|
||||
|
||||
+51
-10
@@ -21,24 +21,63 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
public class CNotes
|
||||
{
|
||||
private readonly List<CVoice> _Voices = new List<CVoice>();
|
||||
|
||||
public CVoice[] Voices
|
||||
public class CVoiceNames
|
||||
{
|
||||
get { return _Voices.ToArray(); }
|
||||
private readonly List<string> _Names = new List<string>();
|
||||
|
||||
public CVoiceNames() {}
|
||||
|
||||
public CVoiceNames(CVoiceNames names)
|
||||
{
|
||||
_Names.AddRange(names._Names);
|
||||
}
|
||||
|
||||
public string this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsSet(index))
|
||||
return _Names[index];
|
||||
return "Part " + (index + 1);
|
||||
}
|
||||
set
|
||||
{
|
||||
_Names.EnsureSize(index + 1, null);
|
||||
_Names[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSet(int index)
|
||||
{
|
||||
return _Names.Count > index && !string.IsNullOrEmpty(_Names[index]);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_Names.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<CVoice> _Voices = new List<CVoice>();
|
||||
public readonly CVoiceNames VoiceNames = new CVoiceNames();
|
||||
|
||||
public CNotes() {}
|
||||
|
||||
public int LinesCount
|
||||
{
|
||||
get { return _Voices.Count; }
|
||||
}
|
||||
|
||||
public CNotes(CNotes notes)
|
||||
{
|
||||
foreach (CVoice voice in notes._Voices)
|
||||
_Voices.Add(new CVoice(voice));
|
||||
VoiceNames = new CVoiceNames(notes.VoiceNames);
|
||||
}
|
||||
|
||||
public IEnumerable<CVoice> Voices
|
||||
{
|
||||
get { return _Voices; }
|
||||
}
|
||||
|
||||
public int VoiceCount
|
||||
{
|
||||
get { return _Voices.Count; }
|
||||
}
|
||||
|
||||
public CVoice GetVoice(int index)
|
||||
@@ -79,9 +118,11 @@ namespace VocaluxeLib.Songs
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
public void Reset(bool resetVoices = false)
|
||||
{
|
||||
_Voices.Clear();
|
||||
if (resetVoices)
|
||||
VoiceNames.Reset();
|
||||
}
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
|
||||
+126
-574
@@ -20,7 +20,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
@@ -45,12 +44,11 @@ namespace VocaluxeLib.Songs
|
||||
Artist = 2,
|
||||
MP3 = 4,
|
||||
BPM = 8,
|
||||
PreviewStart = 16,
|
||||
MedleyStartBeat = 32,
|
||||
MedleyEndBeat = 64
|
||||
MedleyStartBeat = 16,
|
||||
MedleyEndBeat = 32
|
||||
}
|
||||
|
||||
public enum EMedleySource
|
||||
public enum EDataSource
|
||||
{
|
||||
None = 0,
|
||||
Calculated,
|
||||
@@ -59,30 +57,43 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public struct SMedley
|
||||
{
|
||||
public EMedleySource Source;
|
||||
public EDataSource Source;
|
||||
public int StartBeat;
|
||||
public int EndBeat;
|
||||
public float FadeInTime;
|
||||
public float FadeOutTime;
|
||||
}
|
||||
|
||||
public class CSong
|
||||
public struct SShortEnd
|
||||
{
|
||||
public EDataSource Source;
|
||||
public int EndBeat;
|
||||
}
|
||||
|
||||
public struct SPreview
|
||||
{
|
||||
public EDataSource Source;
|
||||
public float StartTime;
|
||||
}
|
||||
|
||||
public partial class CSong
|
||||
{
|
||||
private CTexture _CoverTextureSmall;
|
||||
private CTexture _CoverTextureBig;
|
||||
|
||||
public SMedley Medley;
|
||||
|
||||
public bool CalculateMedley = true;
|
||||
public float PreviewStart;
|
||||
private bool _CalculateMedley = true;
|
||||
public SPreview Preview;
|
||||
|
||||
public int ShortEnd;
|
||||
public SShortEnd ShortEnd;
|
||||
|
||||
public Encoding Encoding = Encoding.Default;
|
||||
public bool ManualEncoding;
|
||||
public string Folder = String.Empty;
|
||||
public string FolderName = String.Empty;
|
||||
public string FileName = String.Empty;
|
||||
public EOffOn Relative = EOffOn.TR_CONFIG_OFF;
|
||||
public bool Relative;
|
||||
|
||||
public string MP3FileName = String.Empty;
|
||||
public string CoverFileName = String.Empty;
|
||||
@@ -117,17 +128,31 @@ namespace VocaluxeLib.Songs
|
||||
public string TitleSorting = String.Empty;
|
||||
public string ArtistSorting = String.Empty;
|
||||
|
||||
public string Creator = "";
|
||||
public string Version = "";
|
||||
public string Source = "";
|
||||
public readonly List<String> UnknownTags = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Start of the song in s (s in txt)
|
||||
/// </summary>
|
||||
public float Start;
|
||||
/// <summary>
|
||||
/// End of the song in s (ms in txt)
|
||||
/// </summary>
|
||||
public float Finish;
|
||||
|
||||
public float BPM = 1f;
|
||||
/// <summary>
|
||||
/// Gap of the mp3 in s (ms in txt)
|
||||
/// </summary>
|
||||
public float Gap;
|
||||
/// <summary>
|
||||
/// Gap of the video in s (s in txt)
|
||||
/// </summary>
|
||||
public float VideoGap;
|
||||
|
||||
public string DuetPart1 = String.Empty;
|
||||
public string DuetPart2 = String.Empty;
|
||||
|
||||
private readonly List<string> _Comment = new List<string>();
|
||||
private string _Comment = "";
|
||||
|
||||
// Sorting
|
||||
public int ID;
|
||||
@@ -136,14 +161,15 @@ namespace VocaluxeLib.Songs
|
||||
private readonly bool _Selected;
|
||||
public bool IsDuet
|
||||
{
|
||||
get { return Notes.Voices.Length > 1; }
|
||||
get { return Notes.VoiceCount > 1; }
|
||||
}
|
||||
|
||||
public readonly List<string> Edition = new List<string>();
|
||||
public readonly List<string> Genre = new List<string>();
|
||||
public readonly List<string> Editions = new List<string>();
|
||||
public readonly List<string> Genres = new List<string>();
|
||||
public string Album = "";
|
||||
public string Year = "";
|
||||
|
||||
public readonly List<string> Language = new List<string>();
|
||||
public readonly List<string> Languages = new List<string>();
|
||||
|
||||
public int DataBaseSongID = -1;
|
||||
public string DateAdded = "";
|
||||
@@ -152,50 +178,47 @@ namespace VocaluxeLib.Songs
|
||||
// Notes
|
||||
public readonly CNotes Notes = new CNotes();
|
||||
|
||||
public EGameMode[] AvailableGameModes
|
||||
public IList<EGameMode> AvailableGameModes
|
||||
{
|
||||
get
|
||||
{
|
||||
var gms = new List<EGameMode> {IsDuet ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL};
|
||||
if (Medley.Source != EMedleySource.None)
|
||||
if (Medley.Source != EDataSource.None)
|
||||
gms.Add(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
gms.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
if (ShortEnd.Source != EDataSource.None)
|
||||
gms.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
|
||||
return gms.ToArray();
|
||||
return gms;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the requested game mode is available
|
||||
/// </summary>
|
||||
/// <param name="gameMode"></param>
|
||||
/// <returns>true if the requested game mode is available</returns>
|
||||
public bool IsGameModeAvailable(EGameMode gameMode)
|
||||
{
|
||||
return AvailableGameModes.Any(gm => gm == gameMode);
|
||||
}
|
||||
|
||||
//No point creating a song without a text file --> Use factory method LoadSong
|
||||
private CSong() {}
|
||||
|
||||
public static CSong LoadSong(string filePath)
|
||||
{
|
||||
var song = new CSong();
|
||||
return song.ReadHeader(filePath) ? song : null;
|
||||
}
|
||||
|
||||
public CSong(CSong song)
|
||||
{
|
||||
_CoverTextureSmall = song._CoverTextureSmall;
|
||||
_CoverTextureBig = song._CoverTextureBig;
|
||||
|
||||
Medley = new SMedley
|
||||
{
|
||||
Source = song.Medley.Source,
|
||||
StartBeat = song.Medley.StartBeat,
|
||||
EndBeat = song.Medley.EndBeat,
|
||||
FadeInTime = song.Medley.FadeInTime,
|
||||
FadeOutTime = song.Medley.FadeOutTime
|
||||
};
|
||||
Medley = song.Medley;
|
||||
|
||||
CalculateMedley = song.CalculateMedley;
|
||||
PreviewStart = song.PreviewStart;
|
||||
_CalculateMedley = song._CalculateMedley;
|
||||
Preview = song.Preview;
|
||||
|
||||
ShortEnd = song.ShortEnd;
|
||||
DuetPart1 = song.DuetPart1;
|
||||
DuetPart2 = song.DuetPart2;
|
||||
|
||||
Encoding = song.Encoding;
|
||||
ManualEncoding = song.ManualEncoding;
|
||||
Folder = song.Folder;
|
||||
FolderName = song.FolderName;
|
||||
FileName = song.FileName;
|
||||
@@ -211,6 +234,13 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
Artist = song.Artist;
|
||||
Title = song.Title;
|
||||
ArtistSorting = song.ArtistSorting;
|
||||
TitleSorting = song.TitleSorting;
|
||||
|
||||
Creator = song.Creator;
|
||||
Version = song.Version;
|
||||
Source = song.Source;
|
||||
UnknownTags = new List<string>(song.UnknownTags);
|
||||
|
||||
Start = song.Start;
|
||||
Finish = song.Finish;
|
||||
@@ -219,28 +249,19 @@ namespace VocaluxeLib.Songs
|
||||
Gap = song.Gap;
|
||||
VideoGap = song.VideoGap;
|
||||
|
||||
_Comment = new List<string>();
|
||||
foreach (string value in song._Comment)
|
||||
_Comment.Add(value);
|
||||
_Comment = song._Comment;
|
||||
|
||||
ID = song.ID;
|
||||
_Visible = song._Visible;
|
||||
_CatIndex = song._CatIndex;
|
||||
_Selected = song._Selected;
|
||||
|
||||
Edition = new List<string>();
|
||||
foreach (string value in song.Edition)
|
||||
Edition.Add(value);
|
||||
|
||||
Genre = new List<string>();
|
||||
foreach (string value in song.Genre)
|
||||
Genre.Add(value);
|
||||
|
||||
Editions = new List<string>(song.Editions);
|
||||
Genres = new List<string>(song.Genres);
|
||||
Album = song.Album;
|
||||
Year = song.Year;
|
||||
|
||||
Language = new List<string>();
|
||||
foreach (string value in song.Language)
|
||||
Language.Add(value);
|
||||
Languages = new List<string>(song.Languages);
|
||||
|
||||
DataBaseSongID = song.DataBaseSongID;
|
||||
DateAdded = song.DateAdded;
|
||||
@@ -249,6 +270,25 @@ namespace VocaluxeLib.Songs
|
||||
Notes = new CNotes(song.Notes);
|
||||
}
|
||||
|
||||
public static CSong LoadSong(string filePath)
|
||||
{
|
||||
var song = new CSong();
|
||||
var loader = new CSongLoader(song);
|
||||
return loader.InitPaths(filePath) && loader.ReadHeader() ? song : null;
|
||||
}
|
||||
|
||||
public bool LoadNotes()
|
||||
{
|
||||
var loader = new CSongLoader(this);
|
||||
return loader.ReadNotes();
|
||||
}
|
||||
|
||||
public bool Save(string filePath)
|
||||
{
|
||||
var writer = new CSongWriter(this);
|
||||
return writer.SaveFile(filePath);
|
||||
}
|
||||
|
||||
public string GetMP3()
|
||||
{
|
||||
return Path.Combine(Folder, MP3FileName);
|
||||
@@ -259,494 +299,6 @@ namespace VocaluxeLib.Songs
|
||||
return Path.Combine(Folder, VideoFileName);
|
||||
}
|
||||
|
||||
public bool ReadHeader(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
Folder = Path.GetDirectoryName(filePath);
|
||||
if (Folder == null)
|
||||
return false;
|
||||
|
||||
foreach (string folder in CBase.Config.GetSongFolder())
|
||||
{
|
||||
if (!Folder.Contains(folder))
|
||||
continue;
|
||||
if (Folder.Length == folder.Length)
|
||||
FolderName = "Songs";
|
||||
else
|
||||
{
|
||||
FolderName = Folder.Substring(folder.Length + 1, Folder.Length - folder.Length - 1);
|
||||
|
||||
int pos = FolderName.IndexOf("\\", StringComparison.Ordinal);
|
||||
if (pos >= 0)
|
||||
FolderName = FolderName.Substring(0, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
FileName = Path.GetFileName(filePath);
|
||||
|
||||
var headerFlags = new EHeaderFlags();
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, Encoding.Default, true);
|
||||
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].ToString().Equals("#"))
|
||||
break;
|
||||
|
||||
int pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos <= 0)
|
||||
continue;
|
||||
string identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
string value = line.Substring(pos + 1, line.Length - pos - 1).Trim();
|
||||
|
||||
if (value != "")
|
||||
{
|
||||
switch (identifier)
|
||||
{
|
||||
case "ENCODING":
|
||||
Encoding = CEncoding.GetEncoding(value);
|
||||
sr.Dispose();
|
||||
sr = null;
|
||||
sr = new StreamReader(filePath, Encoding);
|
||||
|
||||
//Scip everything till encoding
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
line = sr.ReadLine();
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].ToString().Equals("#"))
|
||||
break;
|
||||
|
||||
pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
if (identifier == "ENCODING")
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "TITLE":
|
||||
if (value != "")
|
||||
{
|
||||
Title = value;
|
||||
headerFlags |= EHeaderFlags.Title;
|
||||
}
|
||||
break;
|
||||
case "ARTIST":
|
||||
if (value != "")
|
||||
{
|
||||
Artist = value;
|
||||
headerFlags |= EHeaderFlags.Artist;
|
||||
}
|
||||
break;
|
||||
case "TITLE-ON-SORTING":
|
||||
if (value != "")
|
||||
TitleSorting = value;
|
||||
break;
|
||||
case "ARTIST-ON-SORTING":
|
||||
if (value != "")
|
||||
ArtistSorting = value;
|
||||
break;
|
||||
case "DUETSINGERP1":
|
||||
case "P1":
|
||||
if (value != "")
|
||||
DuetPart1 = value;
|
||||
break;
|
||||
case "DUETSINGERP2":
|
||||
case "P2":
|
||||
if (value != "")
|
||||
DuetPart2 = value;
|
||||
break;
|
||||
case "MP3":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
{
|
||||
MP3FileName = value;
|
||||
headerFlags |= EHeaderFlags.MP3;
|
||||
}
|
||||
else
|
||||
{
|
||||
CBase.Log.LogError("Can't find audio file: " + Path.Combine(Folder, value));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "BPM":
|
||||
if (CHelper.TryParse(value, out BPM))
|
||||
{
|
||||
BPM *= 4;
|
||||
headerFlags |= EHeaderFlags.BPM;
|
||||
}
|
||||
break;
|
||||
case "EDITION":
|
||||
if (value.Length > 1)
|
||||
Edition.Add(value);
|
||||
break;
|
||||
case "GENRE":
|
||||
if (value.Length > 1)
|
||||
Genre.Add(value);
|
||||
break;
|
||||
case "YEAR":
|
||||
int num;
|
||||
if (value.Length == 4 && int.TryParse(value, out num) && num != 0)
|
||||
Year = value;
|
||||
break;
|
||||
case "LANGUAGE":
|
||||
if (value.Length > 1)
|
||||
Language.Add(value);
|
||||
break;
|
||||
case "COMMENT":
|
||||
if (value.Length > 1)
|
||||
_Comment.Add(value);
|
||||
break;
|
||||
case "GAP":
|
||||
if (CHelper.TryParse(value, out Gap))
|
||||
Gap /= 1000f;
|
||||
break;
|
||||
case "COVER":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
CoverFileName = value;
|
||||
break;
|
||||
case "BACKGROUND":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
BackgroundFileName = value;
|
||||
break;
|
||||
case "VIDEO":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
VideoFileName = value;
|
||||
else
|
||||
CBase.Log.LogError("Can't find video file: " + Path.Combine(Folder, value));
|
||||
break;
|
||||
case "VIDEOGAP":
|
||||
CHelper.TryParse(value, out VideoGap);
|
||||
break;
|
||||
case "VIDEOASPECT":
|
||||
CHelper.TryParse(value, out VideoAspect, true);
|
||||
break;
|
||||
case "START":
|
||||
CHelper.TryParse(value, out Start);
|
||||
break;
|
||||
case "END":
|
||||
if (CHelper.TryParse(value, out Finish))
|
||||
Finish /= 1000f;
|
||||
break;
|
||||
case "PREVIEWSTART":
|
||||
if (CHelper.TryParse(value, out PreviewStart))
|
||||
{
|
||||
if (PreviewStart < 0f)
|
||||
PreviewStart = 0f;
|
||||
else
|
||||
headerFlags |= EHeaderFlags.PreviewStart;
|
||||
}
|
||||
break;
|
||||
case "MEDLEYSTARTBEAT":
|
||||
if (int.TryParse(value, out Medley.StartBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyStartBeat;
|
||||
break;
|
||||
case "MEDLEYENDBEAT":
|
||||
if (int.TryParse(value, out Medley.EndBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyEndBeat;
|
||||
break;
|
||||
case "CALCMEDLEY":
|
||||
if (value.ToUpper() == "OFF")
|
||||
CalculateMedley = false;
|
||||
break;
|
||||
case "RELATIVE":
|
||||
if (value.ToUpper() == "YES" && value.ToUpper() != "NO")
|
||||
Relative = EOffOn.TR_CONFIG_ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} //end of while
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
//No other data then header
|
||||
CBase.Log.LogError("Lyrics/Notes missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Title) == 0)
|
||||
{
|
||||
CBase.Log.LogError("Title tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Artist) == 0)
|
||||
{
|
||||
CBase.Log.LogError("Artist tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MP3) == 0)
|
||||
{
|
||||
CBase.Log.LogError("MP3 tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.BPM) == 0)
|
||||
{
|
||||
CBase.Log.LogError("BPM tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
#region check medley tags
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
if (Medley.StartBeat > Medley.EndBeat)
|
||||
{
|
||||
CBase.Log.LogError("MedleyStartBeat is bigger than MedleyEndBeat in file: " + filePath);
|
||||
headerFlags = headerFlags - EHeaderFlags.MedleyStartBeat - EHeaderFlags.MedleyEndBeat;
|
||||
}
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.PreviewStart) == 0 || Math.Abs(PreviewStart) < float.Epsilon)
|
||||
{
|
||||
//PreviewStart is not set or <=0
|
||||
PreviewStart = (headerFlags & EHeaderFlags.MedleyStartBeat) != 0 ? CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) : 0f;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
Medley.Source = EMedleySource.Tag;
|
||||
Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
#endregion check medley tags
|
||||
|
||||
Encoding = sr.CurrentEncoding;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
CBase.Log.LogError("Error reading txt header in file \"" + filePath + "\": " + e.Message);
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
_CheckFiles();
|
||||
|
||||
CBase.DataBase.GetDataBaseSongInfos(Artist, Title, out NumPlayed, out DateAdded, out DataBaseSongID);
|
||||
|
||||
//Before saving this tags to .txt: Check, if ArtistSorting and Artist are equal, then don't save this tag.
|
||||
if (ArtistSorting == "")
|
||||
ArtistSorting = Artist;
|
||||
|
||||
if (TitleSorting == "")
|
||||
TitleSorting = Title;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ReadNotes()
|
||||
{
|
||||
return _ReadNotes(Path.Combine(Folder, FileName));
|
||||
}
|
||||
|
||||
private bool _ReadNotes(string filePath, bool forceReload = false)
|
||||
{
|
||||
//Skip loading if already done and no reload is forced
|
||||
if (NotesLoaded && !forceReload)
|
||||
return true;
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. The file does not exist: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
char tempC = char.MinValue;
|
||||
int currentPos = 0;
|
||||
bool isNewSentence = false;
|
||||
|
||||
int player = 0;
|
||||
int fileLineNo = 0;
|
||||
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, Encoding, true);
|
||||
|
||||
Notes.Reset();
|
||||
|
||||
//Search for Note Beginning
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
sr.ReadLine();
|
||||
fileLineNo++;
|
||||
|
||||
tempC = (char)sr.Peek();
|
||||
if ((tempC == '#') || (tempC == '\r') || (tempC == '\n'))
|
||||
continue;
|
||||
if ((tempC == ':') || (tempC == 'F') || (tempC == '*') || (tempC == 'P'))
|
||||
{
|
||||
tempC = (char)sr.Read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". No lyrics/notes found: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int param2;
|
||||
int param1;
|
||||
switch (tempC)
|
||||
{
|
||||
case 'P':
|
||||
char chr;
|
||||
while ((chr = (char)sr.Read()) == ' ') {}
|
||||
|
||||
int.TryParse(chr.ToString(), out param1);
|
||||
if (param1 == 1)
|
||||
player = 0;
|
||||
else if (param1 == 2)
|
||||
player = 1;
|
||||
else if (param1 == 3)
|
||||
player = 2;
|
||||
else
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Wrong or missing number after \"P\": " + filePath);
|
||||
return false;
|
||||
}
|
||||
sr.ReadLine();
|
||||
break;
|
||||
case ':':
|
||||
case '*':
|
||||
case 'F':
|
||||
sr.Read();
|
||||
param1 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
param2 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
int param3 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
string paramS = sr.ReadLine();
|
||||
|
||||
ENoteType noteType;
|
||||
|
||||
if (tempC.CompareTo('*') == 0)
|
||||
noteType = ENoteType.Golden;
|
||||
else if (tempC.CompareTo('F') == 0)
|
||||
noteType = ENoteType.Freestyle;
|
||||
else
|
||||
noteType = ENoteType.Normal;
|
||||
|
||||
if (Relative == EOffOn.TR_CONFIG_ON)
|
||||
param1 += currentPos;
|
||||
|
||||
if (player != 2)
|
||||
// one singer
|
||||
_ParseNote(player, noteType, param1, param2, param3, paramS);
|
||||
else
|
||||
{
|
||||
// both singer
|
||||
_ParseNote(0, noteType, param1, param2, param3, paramS);
|
||||
_ParseNote(1, noteType, param1, param2, param3, paramS);
|
||||
}
|
||||
isNewSentence = false;
|
||||
break;
|
||||
case '-':
|
||||
if (isNewSentence)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Double sentence break: " + filePath);
|
||||
return false;
|
||||
}
|
||||
sr.Read();
|
||||
param1 = CHelper.TryReadInt(sr);
|
||||
|
||||
if (Relative == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
param1 += currentPos;
|
||||
sr.Read();
|
||||
param2 = CHelper.TryReadInt(sr);
|
||||
currentPos += param2;
|
||||
}
|
||||
|
||||
if (player != 2)
|
||||
// one singer
|
||||
_NewSentence(player, param1);
|
||||
else
|
||||
{
|
||||
// both singer
|
||||
_NewSentence(0, param1);
|
||||
_NewSentence(1, param1);
|
||||
}
|
||||
|
||||
isNewSentence = true;
|
||||
sr.ReadLine();
|
||||
break;
|
||||
default:
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Unexpected or missing character (" + tempC + "): " + filePath);
|
||||
return false;
|
||||
}
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = sr.Read();
|
||||
} while (!sr.EndOfStream && (c == 19 || c == 16 || c == 13 || c == 10));
|
||||
tempC = (char)c;
|
||||
fileLineNo++;
|
||||
} while (!sr.EndOfStream && (tempC != 'E'));
|
||||
|
||||
foreach (CVoice voice in Notes.Voices)
|
||||
voice.UpdateTimings();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". An unhandled exception occured (" + e.Message + "): " + filePath);
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
try
|
||||
{
|
||||
_FindRefrain();
|
||||
_FindShortEnd();
|
||||
NotesLoaded = true;
|
||||
if (IsDuet)
|
||||
_CheckDuet();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. An unhandled exception occured (" + e.Message + "): " + filePath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool _ParseNote(int player, ENoteType noteType, int start, int length, int tone, string text)
|
||||
{
|
||||
var note = new CSongNote(start, length, tone, text, noteType);
|
||||
CVoice voice = Notes.GetVoice(player);
|
||||
return voice.AddNote(note);
|
||||
}
|
||||
|
||||
private void _NewSentence(int player, int start)
|
||||
{
|
||||
CVoice voice = Notes.GetVoice(player);
|
||||
var line = new CSongLine {StartBeat = start};
|
||||
voice.AddLine(line);
|
||||
}
|
||||
|
||||
public void LoadSmallCover()
|
||||
{
|
||||
if (_CoverTextureSmall != null)
|
||||
@@ -765,11 +317,13 @@ namespace VocaluxeLib.Songs
|
||||
if (CoverFileName == "")
|
||||
{
|
||||
List<string> files = CHelper.ListFiles(Folder, "*.jpg");
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.png"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
|
||||
foreach (String file in files)
|
||||
{
|
||||
if (Regex.IsMatch(file, @".[CO].", RegexOptions.IgnoreCase) &&
|
||||
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase)))
|
||||
if (file.ContainsIgnoreCase("[CO]") &&
|
||||
(file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
|
||||
CoverFileName = file;
|
||||
}
|
||||
}
|
||||
@@ -777,11 +331,13 @@ namespace VocaluxeLib.Songs
|
||||
if (BackgroundFileName == "")
|
||||
{
|
||||
List<string> files = CHelper.ListFiles(Folder, "*.jpg");
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.png"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
|
||||
foreach (String file in files)
|
||||
{
|
||||
if (Regex.IsMatch(file, @".[BG].", RegexOptions.IgnoreCase) &&
|
||||
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase)))
|
||||
if (file.ContainsIgnoreCase("[BG]") &&
|
||||
(file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
|
||||
BackgroundFileName = file;
|
||||
}
|
||||
}
|
||||
@@ -789,15 +345,10 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
private void _CheckDuet()
|
||||
{
|
||||
if (DuetPart1 == "")
|
||||
for (int i = 0; i < Notes.VoiceCount; i++)
|
||||
{
|
||||
DuetPart1 = "Part 1";
|
||||
CBase.Log.LogError("Warning: Can't find #P1-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
}
|
||||
if (DuetPart2 == "")
|
||||
{
|
||||
DuetPart2 = "Part 2";
|
||||
CBase.Log.LogError("Warning: Can't find #P2-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
if (!Notes.VoiceNames.IsSet(i))
|
||||
CBase.Log.LogError("Warning: Can't find #P" + (i + 1) + "-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,14 +404,11 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (IsDuet)
|
||||
{
|
||||
Medley.Source = EMedleySource.None;
|
||||
Medley.Source = EDataSource.None;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Medley.Source == EMedleySource.Tag)
|
||||
return;
|
||||
|
||||
if (!CalculateMedley)
|
||||
if (!_CalculateMedley)
|
||||
return;
|
||||
|
||||
List<SSeries> series = _GetSeries();
|
||||
@@ -883,41 +431,44 @@ namespace VocaluxeLib.Songs
|
||||
Medley.StartBeat = voice.Lines[series[longest].Start].FirstNoteBeat;
|
||||
Medley.EndBeat = voice.Lines[series[longest].End].LastNoteBeat;
|
||||
|
||||
bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) + CBase.Settings.GetMedleyMinDuration() >
|
||||
CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM);
|
||||
bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) < CBase.Settings.GetMedleyMinDuration();
|
||||
|
||||
// set end if duration > MedleyMinDuration
|
||||
// set end if duration < MedleyMinDuration
|
||||
|
||||
if (!foundEnd)
|
||||
{
|
||||
for (int i = series[longest].Start + 1; i < voice.NumLines - 1; i++)
|
||||
for (int i = series[longest].End + 1; i < voice.NumLines - 1; i++)
|
||||
{
|
||||
if (CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) + CBase.Settings.GetMedleyMinDuration() >
|
||||
CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM))
|
||||
if (CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) <
|
||||
CBase.Settings.GetMedleyMinDuration())
|
||||
{
|
||||
foundEnd = true;
|
||||
Medley.EndBeat = voice.Lines[i].LastNoteBeat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundEnd)
|
||||
{
|
||||
Medley.Source = EMedleySource.Calculated;
|
||||
Medley.Source = EDataSource.Calculated;
|
||||
Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(PreviewStart) < 0.001)
|
||||
if (Preview.Source == EDataSource.None)
|
||||
{
|
||||
if (Medley.Source == EMedleySource.Calculated)
|
||||
PreviewStart = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM);
|
||||
if (Medley.Source != EDataSource.None)
|
||||
Preview.StartTime = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM);
|
||||
}
|
||||
}
|
||||
|
||||
private void _FindShortEnd()
|
||||
{
|
||||
if (ShortEnd.Source != EDataSource.None)
|
||||
return;
|
||||
|
||||
List<SSeries> series = _GetSeries();
|
||||
if (series == null)
|
||||
return;
|
||||
@@ -934,10 +485,10 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (stop < (voice.Lines[series[i].Start].FirstNoteBeat + ((voice.Lines[series[i].End].LastNoteBeat - voice.Lines[series[i].Start].FirstNoteBeat) / 2)))
|
||||
{
|
||||
ShortEnd = voice.Lines[series[i].Start - 1].LastNote.EndBeat;
|
||||
ShortEnd.EndBeat = voice.Lines[series[i].Start - 1].LastNote.EndBeat;
|
||||
return;
|
||||
}
|
||||
ShortEnd = voice.Lines[series[i].End].LastNote.EndBeat;
|
||||
ShortEnd.EndBeat = voice.Lines[series[i].End].LastNote.EndBeat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -947,12 +498,13 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (line.FirstNoteBeat < stop && line.LastNoteBeat > stop)
|
||||
{
|
||||
ShortEnd = line.LastNoteBeat;
|
||||
ShortEnd.EndBeat = line.LastNoteBeat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ShortEnd = stop;
|
||||
ShortEnd.EndBeat = stop;
|
||||
ShortEnd.Source = EDataSource.Calculated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
public class CSongLine : CLineBase<CSongNote>
|
||||
{
|
||||
private int _StartBeat = int.MinValue;
|
||||
private int _StartBeat = int.MaxValue;
|
||||
private int _EndBeat = int.MinValue;
|
||||
|
||||
#region Constructors
|
||||
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public int StartBeat
|
||||
{
|
||||
get { return _StartBeat; }
|
||||
get { return Math.Min(_StartBeat, FirstNoteBeat); }
|
||||
set
|
||||
{
|
||||
if (value <= FirstNoteBeat)
|
||||
@@ -56,7 +56,7 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public int EndBeat
|
||||
{
|
||||
get { return _EndBeat; }
|
||||
get { return Math.Min(_EndBeat, LastNoteBeat); }
|
||||
set
|
||||
{
|
||||
if (value >= LastNoteBeat)
|
||||
@@ -77,12 +77,19 @@ namespace VocaluxeLib.Songs
|
||||
_Notes.Add(note);
|
||||
else
|
||||
{
|
||||
//Insert AFTER this note
|
||||
int insPos = FindPreviousNote(note.StartBeat);
|
||||
//Check for overlapping notes
|
||||
if (insPos >= 0 && _Notes[insPos].EndBeat > note.StartBeat)
|
||||
return false;
|
||||
if (insPos < _Notes.Count - 1 && _Notes[insPos + 1].StartBeat > note.EndBeat)
|
||||
return false;
|
||||
if (insPos >= 0) //Check note before
|
||||
{
|
||||
if (_Notes[insPos].EndBeat >= note.StartBeat)
|
||||
return false;
|
||||
}
|
||||
if (insPos < _Notes.Count - 1) //Check note after
|
||||
{
|
||||
if (_Notes[insPos + 1].StartBeat <= note.EndBeat)
|
||||
return false;
|
||||
}
|
||||
_Notes.Insert(insPos + 1, note);
|
||||
}
|
||||
return true;
|
||||
@@ -90,11 +97,8 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
{
|
||||
foreach (CSongNote note in _Notes)
|
||||
{
|
||||
if (note.StartBeat < startBeat || note.EndBeat > endBeat)
|
||||
note.NoteType = ENoteType.Freestyle;
|
||||
}
|
||||
foreach (CSongNote note in _Notes.Where(note => note.StartBeat < startBeat || note.EndBeat > endBeat))
|
||||
note.Type = ENoteType.Freestyle;
|
||||
|
||||
VisibleInTimeLine = FirstNoteBeat >= startBeat && LastNoteBeat <= endBeat;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,740 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
/// <summary>
|
||||
/// Part of CSong that is required for note loading
|
||||
/// </summary>
|
||||
public partial class CSong
|
||||
{
|
||||
/// <summary>
|
||||
/// Factor the bpm given in the txt is multiplied with
|
||||
/// </summary>
|
||||
private const int _BPMFactor = 4;
|
||||
|
||||
private class CSongLoader
|
||||
{
|
||||
private readonly CSong _Song;
|
||||
private int _LineNr;
|
||||
|
||||
public CSongLoader(CSong song)
|
||||
{
|
||||
_Song = song;
|
||||
}
|
||||
|
||||
public bool InitPaths(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
_Song.Folder = Path.GetDirectoryName(filePath);
|
||||
if (_Song.Folder == null)
|
||||
return false;
|
||||
|
||||
foreach (string folder in CBase.Config.GetSongFolders().Where(folder => _Song.Folder.StartsWith(folder)))
|
||||
{
|
||||
if (_Song.Folder.Length == folder.Length)
|
||||
_Song.FolderName = "Songs";
|
||||
else
|
||||
{
|
||||
_Song.FolderName = _Song.Folder.Substring(folder.Length + 1);
|
||||
|
||||
int pos = _Song.FolderName.IndexOf("\\", StringComparison.Ordinal);
|
||||
if (pos >= 0)
|
||||
_Song.FolderName = _Song.FolderName.Substring(0, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_Song.FileName = Path.GetFileName(filePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a given message with file name and line#
|
||||
/// </summary>
|
||||
/// <param name="msg">Message</param>
|
||||
/// <param name="error">True prepends "Error: "; False prepends "Warning: "</param>
|
||||
/// <param name="withLineNr">Adds line#</param>
|
||||
private void _LogMsg(string msg, bool error, bool withLineNr)
|
||||
{
|
||||
msg = (error ? "Error: " : "Warning: ") + msg;
|
||||
if (withLineNr)
|
||||
msg += " in line #" + _LineNr;
|
||||
CBase.Log.LogError(msg + " (" + Path.Combine(_Song.Folder, _Song.FileName) + ")");
|
||||
}
|
||||
|
||||
private void _LogError(string msg, bool withLineNr = true)
|
||||
{
|
||||
_LogMsg(msg, true, withLineNr);
|
||||
}
|
||||
|
||||
private void _LogWarning(string msg, bool withLineNr = true)
|
||||
{
|
||||
_LogMsg(msg, false, withLineNr);
|
||||
}
|
||||
|
||||
public bool ReadHeader(bool useSetEncoding = false)
|
||||
{
|
||||
string filePath = Path.Combine(_Song.Folder, _Song.FileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
_Song.Languages.Clear();
|
||||
_Song.Genres.Clear();
|
||||
_Song.UnknownTags.Clear();
|
||||
_Song._Comment = "";
|
||||
_Song.ManualEncoding = false;
|
||||
_Song.Medley.Source = EDataSource.None;
|
||||
_Song._CalculateMedley = true;
|
||||
_Song.Preview.Source = EDataSource.None;
|
||||
_Song.ShortEnd.Source = EDataSource.None;
|
||||
|
||||
var headerFlags = new EHeaderFlags();
|
||||
StreamReader sr = null;
|
||||
_LineNr = 0;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, _Song.Encoding, true);
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
_LineNr++;
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].Equals('#'))
|
||||
break;
|
||||
|
||||
int pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos <= 1)
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
continue;
|
||||
}
|
||||
string identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
if (identifier.Contains(" "))
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
continue;
|
||||
}
|
||||
string value = line.Substring(pos + 1).Trim();
|
||||
|
||||
if (value == "")
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
_LogWarning("Empty value skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (identifier)
|
||||
{
|
||||
case "ENCODING":
|
||||
Encoding newEncoding = value.GetEncoding();
|
||||
_Song.ManualEncoding = true;
|
||||
if (!newEncoding.Equals(sr.CurrentEncoding))
|
||||
{
|
||||
if (useSetEncoding)
|
||||
{
|
||||
_LogWarning("Duplicate encoding ignored");
|
||||
continue;
|
||||
}
|
||||
sr.Dispose();
|
||||
sr = null;
|
||||
_Song.Encoding = newEncoding;
|
||||
return ReadHeader(true);
|
||||
}
|
||||
break;
|
||||
case "TITLE":
|
||||
_Song.Title = value;
|
||||
headerFlags |= EHeaderFlags.Title;
|
||||
break;
|
||||
case "ARTIST":
|
||||
_Song.Artist = value;
|
||||
headerFlags |= EHeaderFlags.Artist;
|
||||
break;
|
||||
case "TITLE-ON-SORTING":
|
||||
_Song.TitleSorting = value;
|
||||
break;
|
||||
case "ARTIST-ON-SORTING":
|
||||
_Song.ArtistSorting = value;
|
||||
break;
|
||||
case "CREATOR":
|
||||
case "AUTHOR":
|
||||
case "AUTOR":
|
||||
_Song.Creator = value;
|
||||
break;
|
||||
case "VERSION":
|
||||
_Song.Version = value;
|
||||
break;
|
||||
case "SOURCE":
|
||||
case "YOUTUBE":
|
||||
_Song.Source = value;
|
||||
break;
|
||||
case "MP3":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
{
|
||||
_Song.MP3FileName = value;
|
||||
headerFlags |= EHeaderFlags.MP3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LogError("Can't find audio file: " + Path.Combine(_Song.Folder, value));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "BPM":
|
||||
if (CHelper.TryParse(value, out _Song.BPM))
|
||||
{
|
||||
_Song.BPM *= _BPMFactor;
|
||||
headerFlags |= EHeaderFlags.BPM;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid BPM value");
|
||||
break;
|
||||
case "EDITION":
|
||||
if (value.Length > 1)
|
||||
_Song.Editions.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid edition");
|
||||
break;
|
||||
case "GENRE":
|
||||
if (value.Length > 1)
|
||||
_Song.Genres.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid genre");
|
||||
break;
|
||||
case "ALBUM":
|
||||
_Song.Album = value;
|
||||
break;
|
||||
case "YEAR":
|
||||
int num;
|
||||
if (value.Length == 4 && int.TryParse(value, out num) && num > 0)
|
||||
_Song.Year = value;
|
||||
else
|
||||
_LogWarning("Invalid year");
|
||||
break;
|
||||
case "LANGUAGE":
|
||||
if (value.Length > 1)
|
||||
_Song.Languages.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid language");
|
||||
break;
|
||||
case "COMMENT":
|
||||
if (!String.IsNullOrEmpty(_Song._Comment))
|
||||
_Song._Comment += "\r\n";
|
||||
_Song._Comment += value;
|
||||
break;
|
||||
case "GAP":
|
||||
if (CHelper.TryParse(value, out _Song.Gap))
|
||||
_Song.Gap /= 1000f;
|
||||
else
|
||||
_LogWarning("Invalid gap");
|
||||
break;
|
||||
case "COVER":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.CoverFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find cover file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "BACKGROUND":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.BackgroundFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find background file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "VIDEO":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.VideoFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find video file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "VIDEOGAP":
|
||||
if (!CHelper.TryParse(value, out _Song.VideoGap))
|
||||
_LogWarning("Invalid videogap");
|
||||
break;
|
||||
case "VIDEOASPECT":
|
||||
if (!CHelper.TryParse(value, out _Song.VideoAspect, true))
|
||||
_LogWarning("Invalid videoaspect");
|
||||
break;
|
||||
case "START":
|
||||
if (!CHelper.TryParse(value, out _Song.Start))
|
||||
_LogWarning("Invalid start");
|
||||
break;
|
||||
case "END":
|
||||
if (CHelper.TryParse(value, out _Song.Finish))
|
||||
_Song.Finish /= 1000f;
|
||||
else
|
||||
_LogWarning("Invalid end");
|
||||
break;
|
||||
case "PREVIEWSTART":
|
||||
if (CHelper.TryParse(value, out _Song.Preview.StartTime) && _Song.Preview.StartTime >= 0f)
|
||||
_Song.Preview.Source = EDataSource.Tag;
|
||||
else
|
||||
_LogWarning("Invalid previewstart");
|
||||
break;
|
||||
case "PREVIEW":
|
||||
if (CHelper.TryParse(value, out _Song.Preview.StartTime) && _Song.Preview.StartTime >= 0f)
|
||||
{
|
||||
//This is stored in ms not like PREVIEWSTART!
|
||||
_Song.Preview.StartTime /= 1000f;
|
||||
_Song.Preview.Source = EDataSource.Tag;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid previewstart");
|
||||
break;
|
||||
case "MEDLEYSTARTBEAT":
|
||||
if (int.TryParse(value, out _Song.Medley.StartBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyStartBeat;
|
||||
else
|
||||
_LogWarning("Invalid medleystartbeat");
|
||||
break;
|
||||
case "MEDLEYENDBEAT":
|
||||
if (int.TryParse(value, out _Song.Medley.EndBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyEndBeat;
|
||||
else
|
||||
_LogWarning("Invalid medleyendbeat");
|
||||
break;
|
||||
case "ENDSHORT":
|
||||
if ((headerFlags & EHeaderFlags.BPM) != 0)
|
||||
{
|
||||
int endTime;
|
||||
if (int.TryParse(value, out endTime) || endTime < 0)
|
||||
{
|
||||
_Song.ShortEnd.EndBeat = (int)CBase.Game.GetBeatFromTime(endTime / 1000f, _Song.BPM, _Song.Gap);
|
||||
_Song.ShortEnd.Source = EDataSource.Tag;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid medleyendbeat");
|
||||
}
|
||||
break;
|
||||
case "CALCMEDLEY":
|
||||
if (value.ToUpper() == "OFF")
|
||||
_Song._CalculateMedley = false;
|
||||
break;
|
||||
case "RELATIVE":
|
||||
if (value.ToUpper() == "YES")
|
||||
_Song.Relative = true;
|
||||
break;
|
||||
case "RESOLUTION":
|
||||
case "NOTESGAP":
|
||||
//Outdated/not used
|
||||
_Song.UnknownTags.Add(line);
|
||||
break;
|
||||
default:
|
||||
if (identifier.StartsWith("DUETSINGER"))
|
||||
{
|
||||
identifier = identifier.Substring(10);
|
||||
if (identifier.StartsWith("P")) // fix for missing "P"
|
||||
identifier = "P" + identifier;
|
||||
}
|
||||
if (identifier.StartsWith("P"))
|
||||
{
|
||||
int player;
|
||||
if (int.TryParse(identifier.Substring(1).Trim(), out player))
|
||||
{
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
_Song.Notes.VoiceNames[curPlayer] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
_LogWarning("Unknown tag: #" + identifier);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} //end of while
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
//No other data then header
|
||||
_LogError("Lyrics/Notes missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Title) == 0)
|
||||
{
|
||||
_LogError("Title tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Artist) == 0)
|
||||
{
|
||||
_LogError("Artist tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MP3) == 0)
|
||||
{
|
||||
_LogError("MP3 tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.BPM) == 0)
|
||||
{
|
||||
_LogError("BPM tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
#region check medley tags
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
if (_Song.Medley.StartBeat > _Song.Medley.EndBeat)
|
||||
{
|
||||
_LogError("MedleyStartBeat is bigger than MedleyEndBeat in file", false);
|
||||
headerFlags = headerFlags - EHeaderFlags.MedleyStartBeat - EHeaderFlags.MedleyEndBeat;
|
||||
}
|
||||
}
|
||||
|
||||
if (_Song.Preview.Source == EDataSource.None)
|
||||
{
|
||||
//PreviewStart is not set or <=0
|
||||
_Song.Preview.StartTime = (headerFlags & EHeaderFlags.MedleyStartBeat) != 0 ? CBase.Game.GetTimeFromBeats(_Song.Medley.StartBeat, _Song.BPM) : 0f;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
_Song.Medley.Source = EDataSource.Tag;
|
||||
_Song.Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
_Song.Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
#endregion check medley tags
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
_LogError("Error reading txt header" + e.Message, false);
|
||||
return false;
|
||||
}
|
||||
_Song.Encoding = sr.CurrentEncoding;
|
||||
sr.Dispose();
|
||||
_Song._CheckFiles();
|
||||
|
||||
CBase.DataBase.GetDataBaseSongInfos(_Song.Artist, _Song.Title, out _Song.NumPlayed, out _Song.DateAdded, out _Song.DataBaseSongID);
|
||||
|
||||
//Before saving this tags to .txt: Check, if ArtistSorting and Artist are equal, then don't save this tag.
|
||||
if (String.IsNullOrEmpty(_Song.ArtistSorting))
|
||||
_Song.ArtistSorting = _Song.Artist;
|
||||
|
||||
if (String.IsNullOrEmpty(_Song.TitleSorting))
|
||||
_Song.TitleSorting = _Song.Title;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum ENoteReadMode
|
||||
{
|
||||
Normal,
|
||||
ZeroBased,
|
||||
OneBased
|
||||
}
|
||||
|
||||
private class CAutoChanges
|
||||
{
|
||||
public int ZeroLengthNoteCt;
|
||||
public int OverlapNoteCt;
|
||||
public int NoTextNoteCt;
|
||||
public int NoLengthBreakCt;
|
||||
public int AjustedBreakCt;
|
||||
public int InvalidPosBreakCt;
|
||||
|
||||
public bool IsModified
|
||||
{
|
||||
get { return ZeroLengthNoteCt + OverlapNoteCt + NoTextNoteCt + NoLengthBreakCt + AjustedBreakCt + InvalidPosBreakCt > 0; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = "";
|
||||
int skippedNotesCt = ZeroLengthNoteCt + OverlapNoteCt + NoTextNoteCt;
|
||||
if (skippedNotesCt > 0)
|
||||
result += "Skipped " + skippedNotesCt + " notes (0-Length: " + ZeroLengthNoteCt + ", Overlapping: " + OverlapNoteCt + ", No text: " + NoTextNoteCt + ")\r\n";
|
||||
if (InvalidPosBreakCt > 0)
|
||||
result += "Skipped " + InvalidPosBreakCt + " line breaks (Invalid position)\r\n";
|
||||
int adjustedBreakCt = AjustedBreakCt + NoLengthBreakCt;
|
||||
if (adjustedBreakCt > 0)
|
||||
result += "Adjusted " + adjustedBreakCt + " line breaks (Overlapping previous note: " + AjustedBreakCt + ", No length: " + NoLengthBreakCt + ")\r\n";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private ENoteReadMode _CurrentReadMode = ENoteReadMode.Normal;
|
||||
private const int _MaxZeroNoteCt = 1;
|
||||
private const int _MaxOverlapNoteCt = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Read notes. First try to read notes normally (assume standard)<br/>
|
||||
/// If there are more than _MaxZeroNoteCt with length < 1, try to read notes adding 1 to length<br/>
|
||||
/// Then if there are more than _MaxOverlapNoteCt fallback to first version ignoring notes with length < 1
|
||||
/// </summary>
|
||||
/// <param name="forceReload"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadNotes(bool forceReload = false)
|
||||
{
|
||||
//Skip loading if already done and no reload is forced
|
||||
if (_Song.NotesLoaded && !forceReload)
|
||||
return true;
|
||||
|
||||
string filePath = Path.Combine(_Song.Folder, _Song.FileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
_LogError("The file does not exist", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int currentBeat = 0; //Used for relative songs
|
||||
CSongNote lastNote = null; //Holds last parsed note. Get's reset on player change
|
||||
bool endFound = false; // True if end tag was found
|
||||
|
||||
int player = 1;
|
||||
_LineNr = 0;
|
||||
|
||||
char[] trimChars = {' ', ':'};
|
||||
char[] splitChars = {' '};
|
||||
|
||||
var changesMade = new CAutoChanges();
|
||||
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, _Song.Encoding, true);
|
||||
|
||||
_Song.Notes.Reset();
|
||||
|
||||
//Search for Note Beginning
|
||||
while (!sr.EndOfStream && !endFound)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
_LineNr++;
|
||||
|
||||
if (String.IsNullOrEmpty(line))
|
||||
continue;
|
||||
|
||||
char tag = line[0];
|
||||
//Remove tag and potential space
|
||||
line = (line.Length >= 2 && line[1] == ' ') ? line.Substring(2) : line.Substring(1);
|
||||
|
||||
int beat, length;
|
||||
switch (tag)
|
||||
{
|
||||
case '#':
|
||||
continue;
|
||||
case 'E':
|
||||
endFound = true;
|
||||
break;
|
||||
case 'P':
|
||||
line = line.Trim(trimChars);
|
||||
|
||||
if (!int.TryParse(line, out player))
|
||||
{
|
||||
_LogError("Wrong or missing number after \"P\"");
|
||||
return false;
|
||||
}
|
||||
currentBeat = 0;
|
||||
lastNote = null;
|
||||
break;
|
||||
case ':':
|
||||
case '*':
|
||||
case 'F':
|
||||
string[] noteData = line.Split(splitChars, 4);
|
||||
if (noteData.Length < 4)
|
||||
{
|
||||
if (noteData.Length == 3)
|
||||
{
|
||||
_LogWarning("Ignored note without text");
|
||||
changesMade.NoTextNoteCt++;
|
||||
continue;
|
||||
}
|
||||
_LogError("Invalid note found");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
int tone;
|
||||
if (!int.TryParse(noteData[0], out beat) || !int.TryParse(noteData[1], out length) || !int.TryParse(noteData[2], out tone))
|
||||
{
|
||||
_LogError("Invalid note found (non-numeric values)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
string text = noteData[3].TrimMultipleWs();
|
||||
if (text == "")
|
||||
{
|
||||
_LogWarning("Ignored note without text");
|
||||
changesMade.NoTextNoteCt++;
|
||||
continue;
|
||||
}
|
||||
if (_CurrentReadMode == ENoteReadMode.ZeroBased)
|
||||
length++;
|
||||
if (length < 1)
|
||||
{
|
||||
changesMade.ZeroLengthNoteCt++;
|
||||
if (_CurrentReadMode == ENoteReadMode.Normal && changesMade.ZeroLengthNoteCt > _MaxZeroNoteCt && changesMade.OverlapNoteCt <= _MaxOverlapNoteCt)
|
||||
{
|
||||
_LogWarning("Found more than " + _MaxZeroNoteCt + " note with length < 1. Trying alternative read mode.");
|
||||
_CurrentReadMode = ENoteReadMode.ZeroBased;
|
||||
sr.Dispose();
|
||||
return ReadNotes(true);
|
||||
}
|
||||
_LogWarning("Ignored note with length < 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
ENoteType noteType;
|
||||
|
||||
if (tag.Equals('*'))
|
||||
noteType = ENoteType.Golden;
|
||||
else if (tag.Equals('F'))
|
||||
noteType = ENoteType.Freestyle;
|
||||
else
|
||||
noteType = ENoteType.Normal;
|
||||
|
||||
if (_Song.Relative)
|
||||
beat += currentBeat;
|
||||
|
||||
bool ignored = false;
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
{
|
||||
//Create the note here as we want independent instances in the lines. Otherwhise we can't modify them later
|
||||
lastNote = new CSongNote(beat, length, tone, text, noteType);
|
||||
if (!_AddNote(curPlayer, lastNote))
|
||||
{
|
||||
if (!ignored)
|
||||
{
|
||||
ignored = true;
|
||||
changesMade.OverlapNoteCt++;
|
||||
if (changesMade.OverlapNoteCt > _MaxOverlapNoteCt && _CurrentReadMode == ENoteReadMode.ZeroBased)
|
||||
{
|
||||
_LogWarning("Found more than " + _MaxOverlapNoteCt + " overlapping notes. Using standard mode.");
|
||||
_CurrentReadMode = ENoteReadMode.OneBased;
|
||||
sr.Dispose();
|
||||
return ReadNotes(true);
|
||||
}
|
||||
}
|
||||
_LogWarning("Ignored note for player " + (curPlayer + 1) + " because it overlaps with other note");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
string[] lineBreakData = line.Split(splitChars);
|
||||
if (lineBreakData.Length < 1)
|
||||
{
|
||||
_LogError("Invalid line break found (No beat)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
if (!int.TryParse(lineBreakData[0], out beat))
|
||||
{
|
||||
_LogError("Invalid line break found (Non-numeric value)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_Song.Relative)
|
||||
{
|
||||
beat += currentBeat;
|
||||
if (lineBreakData.Length < 2 || !int.TryParse(lineBreakData[1], out length))
|
||||
{
|
||||
_LogWarning("Missing line break length");
|
||||
changesMade.NoLengthBreakCt++;
|
||||
currentBeat = beat;
|
||||
}
|
||||
else
|
||||
currentBeat += length;
|
||||
}
|
||||
|
||||
if (lastNote != null && beat <= lastNote.EndBeat)
|
||||
{
|
||||
_LogWarning("Line break is before previous note end. Adjusted.");
|
||||
changesMade.AjustedBreakCt++;
|
||||
if (_Song.Relative)
|
||||
currentBeat += lastNote.EndBeat - beat + 1;
|
||||
beat = lastNote.EndBeat + 1;
|
||||
}
|
||||
|
||||
if (beat < 1)
|
||||
{
|
||||
_LogWarning("Ignored line break because position is < 1");
|
||||
changesMade.InvalidPosBreakCt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
{
|
||||
if (!_NewSentence(curPlayer, beat))
|
||||
_LogWarning("Ignored line break for player " + (curPlayer + 1) + " (Overlapping or duplicate)");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_LogError("Unexpected or missing character (" + tag + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(i);
|
||||
int emptyLines = voice.RemoveEmptyLines();
|
||||
if (emptyLines > 0)
|
||||
_LogWarning("Removed " + emptyLines + " empty lines from P" + ". This often indicates a problem with the line breaks in the file", false);
|
||||
voice.UpdateTimings();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_LogError("An unhandled exception occured (" + e.Message + ")");
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
try
|
||||
{
|
||||
_Song._FindRefrain();
|
||||
_Song._FindShortEnd();
|
||||
_Song.NotesLoaded = true;
|
||||
if (_Song.IsDuet)
|
||||
_Song._CheckDuet();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_LogError("An unhandled exception occured (" + e.Message + ")", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (changesMade.IsModified)
|
||||
{
|
||||
string msg = "Automatic changes have been made to " + filePath + " Please check result!\r\n" + changesMade;
|
||||
CBase.Log.LogError("Warning: " + msg);
|
||||
if (CBase.Config.GetSaveModifiedSongs() == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
string name = Path.GetFileNameWithoutExtension(_Song.FileName);
|
||||
_Song.Save(Path.Combine(_Song.Folder, name + ".fix"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool _AddNote(int player, CSongNote note)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(player);
|
||||
return voice.AddNote(note, false);
|
||||
}
|
||||
|
||||
private bool _NewSentence(int player, int start)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(player);
|
||||
return voice.AddLine(start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,20 +25,20 @@ namespace VocaluxeLib.Songs
|
||||
#region Contructors
|
||||
public CSongNote(CSongNote note) : base(note)
|
||||
{
|
||||
NoteType = note.NoteType;
|
||||
Type = note.Type;
|
||||
Text = note.Text;
|
||||
}
|
||||
|
||||
public CSongNote(int startBeat, int duration, int tone, string text, ENoteType noteType)
|
||||
: base(startBeat, duration, tone)
|
||||
{
|
||||
NoteType = noteType;
|
||||
Type = noteType;
|
||||
Text = text;
|
||||
}
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
public ENoteType NoteType { get; set; }
|
||||
public ENoteType Type { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (NoteType)
|
||||
switch (Type)
|
||||
{
|
||||
case ENoteType.Normal:
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
public partial class CSong
|
||||
{
|
||||
private class CSongWriter
|
||||
{
|
||||
private readonly CSong _Song;
|
||||
private TextWriter _Tw;
|
||||
|
||||
public CSongWriter(CSong song)
|
||||
{
|
||||
_Song = song;
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, string value)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(value))
|
||||
_Tw.WriteLine("#" + id.ToUpper() + ":" + value);
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, bool value)
|
||||
{
|
||||
if (value)
|
||||
_WriteHeaderEntry(id, "YES");
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, float value, float def = 0f)
|
||||
{
|
||||
if (Math.Abs(value - def) > 0.0001)
|
||||
_WriteHeaderEntry(id, value.ToInvariantString());
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, int value, int def = 0)
|
||||
{
|
||||
if (value != def)
|
||||
_WriteHeaderEntry(id, value.ToString());
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntrys(string id, ICollection<string> value)
|
||||
{
|
||||
if (value == null || value.Count <= 0)
|
||||
return;
|
||||
foreach (String val in value)
|
||||
_WriteHeaderEntry(id, val);
|
||||
}
|
||||
|
||||
private void _WriteHeader()
|
||||
{
|
||||
if (_Song.ManualEncoding)
|
||||
_WriteHeaderEntry("ENCODING", _Song.Encoding.GetEncodingName());
|
||||
_WriteHeaderEntry("CREATOR", _Song.Creator);
|
||||
_WriteHeaderEntry("VERSION", _Song.Version);
|
||||
_WriteHeaderEntry("SOURCE", _Song.Source);
|
||||
if (!String.IsNullOrEmpty(_Song._Comment))
|
||||
{
|
||||
string comment = _Song._Comment.Replace("\r\n", "\n").Replace('\r', '\n');
|
||||
char[] splitChar = {'\n'};
|
||||
_WriteHeaderEntrys("COMMENT", comment.Split(splitChar));
|
||||
}
|
||||
_WriteHeaderEntry("TITLE", _Song.Title);
|
||||
_WriteHeaderEntry("ARTIST", _Song.Artist);
|
||||
if (!_Song.Title.Equals(_Song.TitleSorting))
|
||||
_WriteHeaderEntry("TITLE-ON-SORTING", _Song.TitleSorting);
|
||||
if (!_Song.Artist.Equals(_Song.ArtistSorting))
|
||||
_WriteHeaderEntry("ARTIST-ON-SORTING", _Song.ArtistSorting);
|
||||
_WriteHeaderEntrys("EDITION", _Song.Editions);
|
||||
_WriteHeaderEntrys("GENRE", _Song.Genres);
|
||||
_WriteHeaderEntrys("LANGUAGE", _Song.Languages);
|
||||
_WriteHeaderEntry("ALBUM", _Song.Album);
|
||||
_WriteHeaderEntry("YEAR", _Song.Year);
|
||||
_WriteHeaderEntry("MP3", _Song.MP3FileName);
|
||||
_WriteHeaderEntry("COVER", _Song.CoverFileName);
|
||||
_WriteHeaderEntry("BACKGROUND", _Song.BackgroundFileName);
|
||||
_WriteHeaderEntry("VIDEO", _Song.VideoFileName);
|
||||
_WriteHeaderEntry("VIDEOGAP", _Song.VideoGap);
|
||||
if (_Song.VideoAspect != EAspect.Crop)
|
||||
_WriteHeaderEntry("VIDEOASPECT", _Song.VideoAspect.ToString());
|
||||
_WriteHeaderEntry("RELATIVE", _Song.Relative);
|
||||
_WriteHeaderEntry("BPM", _Song.BPM / _BPMFactor);
|
||||
_WriteHeaderEntry("GAP", (int)(_Song.Gap * 1000f));
|
||||
if (_Song.Preview.Source == EDataSource.Tag)
|
||||
_WriteHeaderEntry("PREVIEWSTART", _Song.Preview.StartTime);
|
||||
_WriteHeaderEntry("START", _Song.Start);
|
||||
_WriteHeaderEntry("END", (int)(_Song.Finish * 1000f));
|
||||
if (_Song.ShortEnd.Source == EDataSource.Tag)
|
||||
_WriteHeaderEntry("ENDSHORT", (int)(CBase.Game.GetTimeFromBeats(_Song.ShortEnd.EndBeat, _Song.BPM) + _Song.Gap) * 1000);
|
||||
if (!_Song._CalculateMedley)
|
||||
_WriteHeaderEntry("CALCMEDLEY", "OFF");
|
||||
if (_Song.Medley.Source == EDataSource.Tag)
|
||||
{
|
||||
_WriteHeaderEntry("MEDLEYSTARTBEAT", _Song.Medley.StartBeat);
|
||||
_WriteHeaderEntry("MEDLEYENDBEAT", _Song.Medley.EndBeat);
|
||||
}
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
if (_Song.Notes.VoiceNames.IsSet(i))
|
||||
_WriteHeaderEntry("P" + i, _Song.Notes.VoiceNames[i]);
|
||||
}
|
||||
foreach (string addLine in _Song.UnknownTags)
|
||||
_Tw.WriteLine(addLine);
|
||||
}
|
||||
|
||||
private void _WriteNotes()
|
||||
{
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(i);
|
||||
if (_Song.Notes.VoiceCount > 1)
|
||||
_Tw.WriteLine("P" + Math.Pow(2, i));
|
||||
bool firstLine = true;
|
||||
int currentBeat = 0;
|
||||
foreach (CSongLine line in voice.Lines)
|
||||
{
|
||||
if (!firstLine)
|
||||
{
|
||||
string lineTxt = "- " + (line.StartBeat - currentBeat);
|
||||
if (_Song.Relative)
|
||||
{
|
||||
lineTxt += " " + (line.FirstNoteBeat - currentBeat);
|
||||
currentBeat = line.FirstNoteBeat;
|
||||
}
|
||||
_Tw.WriteLine(lineTxt);
|
||||
}
|
||||
else
|
||||
firstLine = false;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
string tag;
|
||||
switch (note.Type)
|
||||
{
|
||||
case ENoteType.Normal:
|
||||
tag = ":";
|
||||
break;
|
||||
case ENoteType.Golden:
|
||||
tag = "*";
|
||||
break;
|
||||
case ENoteType.Freestyle:
|
||||
tag = "F";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("Note type " + note.Type);
|
||||
}
|
||||
_Tw.WriteLine(tag + " " + (note.StartBeat - currentBeat) + " " + note.Duration + " " + note.Tone + " " + note.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
_Tw.WriteLine("E");
|
||||
}
|
||||
|
||||
public bool SaveFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
_Tw = new StreamWriter(filePath, false, _Song.Encoding);
|
||||
_WriteHeader();
|
||||
_WriteNotes();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Unhandled exception while writing " + filePath + ": " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace VocaluxeLib.Songs
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public double Points;
|
||||
public new double Points;
|
||||
// for drawing player notes
|
||||
public bool Hit
|
||||
{
|
||||
|
||||
+85
-14
@@ -15,6 +15,7 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -67,7 +68,11 @@ namespace VocaluxeLib.Songs
|
||||
}
|
||||
|
||||
#region Methods
|
||||
//Find last line with StartBeat<=Beat
|
||||
/// <summary>
|
||||
/// Find last line with StartBeat<=Beat
|
||||
/// </summary>
|
||||
/// <param name="beat"></param>
|
||||
/// <returns></returns>
|
||||
public int FindPreviousLine(int beat)
|
||||
{
|
||||
//If no line -> No previous line
|
||||
@@ -92,15 +97,49 @@ namespace VocaluxeLib.Songs
|
||||
return start;
|
||||
}
|
||||
|
||||
public void AddLine(CSongLine line)
|
||||
public bool AddLine(CSongLine line, bool updateTimings = true)
|
||||
{
|
||||
if (_Lines.Count == 0)
|
||||
_Lines.Add(line);
|
||||
else
|
||||
{
|
||||
int insPos = FindPreviousLine(line.StartBeat);
|
||||
//Check if previous line ends before this one
|
||||
if (insPos >= 0 && _Lines[insPos].LastNoteBeat > line.StartBeat)
|
||||
return false;
|
||||
//Check if next line starts before this one ends
|
||||
if (insPos + 1 < _Lines.Count && _Lines[insPos + 1].FirstNoteBeat < line.LastNoteBeat)
|
||||
return false;
|
||||
_Lines.Insert(insPos + 1, line);
|
||||
}
|
||||
if (updateTimings)
|
||||
UpdateTimings();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddLine(int startBeat)
|
||||
{
|
||||
int insPos = FindPreviousLine(startBeat);
|
||||
//Check for actual notes (startbeat may be lower than first note)
|
||||
while (insPos >= 0 && _Lines[insPos].NoteCount > 0 && _Lines[insPos].FirstNoteBeat > startBeat)
|
||||
insPos--;
|
||||
CSongLine line = new CSongLine {StartBeat = startBeat};
|
||||
if (insPos >= 0)
|
||||
{
|
||||
CSongLine prevLine = _Lines[insPos];
|
||||
//We already have a line break here
|
||||
if (prevLine.StartBeat == startBeat && (prevLine.NoteCount==0 || prevLine.FirstNoteBeat == startBeat))
|
||||
return false;
|
||||
//Maybe we have to split the previous line
|
||||
while (prevLine.NoteCount > 0 && prevLine.LastNote.StartBeat >= startBeat)
|
||||
{
|
||||
//throw new Exception("This should not happen on song loading!");
|
||||
line.AddNote(prevLine.LastNote);
|
||||
prevLine.DeleteNote(prevLine.NoteCount - 1);
|
||||
}
|
||||
}
|
||||
_Lines.Insert(insPos + 1, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DeleteLine(int index)
|
||||
@@ -119,15 +158,26 @@ namespace VocaluxeLib.Songs
|
||||
_Lines.Clear();
|
||||
}
|
||||
|
||||
public bool AddNote(CSongNote note, bool updateTimings = false)
|
||||
public bool AddNote(CSongNote note, bool updateTimings = true)
|
||||
{
|
||||
int lineIndex = FindPreviousLine(note.StartBeat);
|
||||
if (lineIndex + 1 < _Lines.Count && _Lines[lineIndex + 1].FirstNoteBeat < note.EndBeat) //First note in next line starts before this one ends
|
||||
return false;
|
||||
if (lineIndex < 0)
|
||||
{
|
||||
//Note is before ALL lines
|
||||
var line = new CSongLine {StartBeat = note.StartBeat};
|
||||
line.AddNote(note);
|
||||
_Lines.Insert(0, line);
|
||||
if (_Lines.Count > 0)
|
||||
{
|
||||
//Add to first line
|
||||
if (!_Lines[0].AddNote(note))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var line = new CSongLine();
|
||||
line.AddNote(note);
|
||||
_Lines.Add(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -139,24 +189,27 @@ namespace VocaluxeLib.Songs
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool InsertNote(CSongNote note, int lineIndex, bool updateTimings = false)
|
||||
/*Check this first for consistency (next line might be affected)
|
||||
* public bool InsertNote(CSongNote note, int lineIndex, bool updateTimings = false)
|
||||
{
|
||||
if (_Lines.Count > lineIndex && _Lines[lineIndex].StartBeat <= note.StartBeat)
|
||||
{
|
||||
_Lines[lineIndex].AddNote(note);
|
||||
if (!_Lines[lineIndex].AddNote(note))
|
||||
return false;
|
||||
if (updateTimings)
|
||||
UpdateTimings();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
public void UpdateTimings()
|
||||
{
|
||||
CSongNote lastNote;
|
||||
|
||||
if (_Lines.Count > 0)
|
||||
_Lines[0].StartBeat = -10000;
|
||||
if (_Lines.Count == 0)
|
||||
return;
|
||||
_Lines[0].StartBeat = -10000;
|
||||
|
||||
for (int i = 1; i < _Lines.Count; i++)
|
||||
{
|
||||
@@ -191,11 +244,24 @@ namespace VocaluxeLib.Songs
|
||||
_Lines[i].StartBeat = s;
|
||||
_Lines[i - 1].EndBeat = min;
|
||||
}
|
||||
else if (firstNote != null)
|
||||
{
|
||||
_Lines[i - 1].EndBeat = Math.Min(_Lines[i - 1].StartBeat, firstNote.StartBeat - 2);
|
||||
_Lines[i].StartBeat = Math.Max(_Lines[i - 1].EndBeat, firstNote.StartBeat - 2);
|
||||
}
|
||||
else if (lastNote != null)
|
||||
{
|
||||
_Lines[i - 1].EndBeat = lastNote.EndBeat;
|
||||
_Lines[i].StartBeat = Math.Max(lastNote.EndBeat, _Lines[i].StartBeat); //Prefer current setting
|
||||
}
|
||||
else
|
||||
{
|
||||
//No note
|
||||
_Lines[i - 1].EndBeat = _Lines[i - 1].StartBeat; //Assume at least startbeats were set right
|
||||
}
|
||||
}
|
||||
|
||||
lastNote = _Lines[_Lines.Count - 1].LastNote;
|
||||
if (lastNote != null)
|
||||
_Lines[_Lines.Count - 1].EndBeat = lastNote.EndBeat;
|
||||
_Lines[_Lines.Count - 1].EndBeat = Math.Max(_Lines[_Lines.Count - 1].LastNoteBeat, _Lines[_Lines.Count - 1].StartBeat); //Use note or (when not set) start beat
|
||||
}
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
@@ -204,5 +270,10 @@ namespace VocaluxeLib.Songs
|
||||
line.SetMedley(startBeat, endBeat);
|
||||
}
|
||||
#endregion Methods
|
||||
|
||||
public int RemoveEmptyLines()
|
||||
{
|
||||
return _Lines.RemoveAll(line => line.NoteCount == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="IBasic.cs" />
|
||||
<Compile Include="Menu\CBackground.cs" />
|
||||
@@ -174,9 +175,11 @@
|
||||
<Compile Include="Menu\SongMenu\CSongMenuList.cs" />
|
||||
<Compile Include="Menu\SongMenu\CSongMenuTileBoard.cs" />
|
||||
<Compile Include="Menu\SongMenu\ISongMenu.cs" />
|
||||
<Compile Include="Songs\CSongWriter.cs" />
|
||||
<Compile Include="Songs\CSungLine.cs" />
|
||||
<Compile Include="Songs\CSungNote.cs" />
|
||||
<Compile Include="Songs\CVoice.cs" />
|
||||
<Compile Include="Songs\CSongLoader.cs" />
|
||||
<Compile Include="Structs.cs" />
|
||||
<Compile Include="PartyModes\CPartyMode.cs" />
|
||||
<Compile Include="PartyModes\CPartyModeNone.cs" />
|
||||
@@ -195,4 +198,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
Reference in new issue
Block a user