Merge branch 'SongLoader' into develop

This commit is contained in:
Flamefire committed 2013-10-14 22:02:18 +02:00
commit 91afb830b5
37 files changed
+1549 -902

No files matched your search

@@ -504,7 +504,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
CBase.BackgroundMusic.SetStatus(true); CBase.BackgroundMusic.SetStatus(true);
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false); _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.SetStreamVolume(_PreviewStream, 0f);
CBase.Sound.Play(_PreviewStream); CBase.Sound.Play(_PreviewStream);
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f); CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
@@ -528,7 +528,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
CBase.BackgroundMusic.SetStatus(true); CBase.BackgroundMusic.SetStatus(true);
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false); _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.SetStreamVolume(_PreviewStream, 0f);
CBase.Sound.Play(_PreviewStream); CBase.Sound.Play(_PreviewStream);
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f); CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
+1 -4
View File
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{6F3E1874-F28A-40E9-AFBD-31934D593678} = {6F3E1874-F28A-40E9-AFBD-31934D593678} {6F3E1874-F28A-40E9-AFBD-31934D593678} = {6F3E1874-F28A-40E9-AFBD-31934D593678}
@@ -154,7 +154,4 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal EndGlobal
-16
View File
@@ -90,11 +90,6 @@ namespace Vocaluxe.Base
get { return _CurrentPlaylistElement.SongID; } get { return _CurrentPlaylistElement.SongID; }
} }
public static bool Duet
{
get { return _CurrentPlaylistElement.Duet; }
}
public static bool SongHasVideo public static bool SongHasVideo
{ {
get { return File.Exists(_CurrentPlaylistElement.VideoFilePath); } 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) public CPlaylistElement(CSong song)
{ {
MusicFilePath = string.Empty; MusicFilePath = string.Empty;
+5
View File
@@ -37,6 +37,7 @@ namespace Vocaluxe.Base
// Debug // Debug
public static EDebugLevel DebugLevel = EDebugLevel.TR_CONFIG_OFF; public static EDebugLevel DebugLevel = EDebugLevel.TR_CONFIG_OFF;
public static EOffOn SaveModifiedSongs = EOffOn.TR_CONFIG_OFF;
// Graphics // Graphics
#if WIN #if WIN
@@ -169,6 +170,7 @@ namespace Vocaluxe.Base
return; return;
xmlReader.TryGetEnumValue("//root/Debug/DebugLevel", ref DebugLevel); xmlReader.TryGetEnumValue("//root/Debug/DebugLevel", ref DebugLevel);
xmlReader.TryGetEnumValue("//root/Debug/SaveModifiedSongs", ref SaveModifiedSongs);
#region Graphics #region Graphics
xmlReader.TryGetEnumValue("//root/Graphics/Renderer", ref Renderer); xmlReader.TryGetEnumValue("//root/Graphics/Renderer", ref Renderer);
@@ -328,6 +330,9 @@ namespace Vocaluxe.Base
writer.WriteComment("DebugLevel: " + CHelper.ListStrings(Enum.GetNames(typeof(EDebugLevel)))); writer.WriteComment("DebugLevel: " + CHelper.ListStrings(Enum.GetNames(typeof(EDebugLevel))));
writer.WriteElementString("DebugLevel", Enum.GetName(typeof(EDebugLevel), DebugLevel)); 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(); writer.WriteEndElement();
#endregion Debug #endregion Debug
+7 -7
View File
@@ -234,7 +234,7 @@ namespace Vocaluxe.Base
for (int beat = _LastEvalBeat + 1; beat <= RecordedBeat; beat++) for (int beat = _LastEvalBeat + 1; beat <= RecordedBeat; beat++)
{ {
if ((_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_MEDLEY && song.Medley.EndBeat == 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; Players[p].SongFinished = true;
CSongLine[] lines = song.Notes.GetVoice(Players[p].VoiceNr).Lines; CSongLine[] lines = song.Notes.GetVoice(Players[p].VoiceNr).Lines;
@@ -290,7 +290,7 @@ namespace Vocaluxe.Base
//CSound.RecordSetTone(p, Tone); //CSound.RecordSetTone(p, Tone);
double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[note].PointsForBeat / double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[note].PointsForBeat /
song.Notes.GetVoice(Players[p].VoiceNr).Points; 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].PointsGoldenNotes += points;
Players[p].Points += points; Players[p].Points += points;
@@ -384,7 +384,7 @@ namespace Vocaluxe.Base
{ {
if (note.StartBeat < nextStart) 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].PointsGoldenNotes += note.Points;
Players[p].Points += note.Points; Players[p].Points += note.Points;
} }
@@ -394,7 +394,7 @@ namespace Vocaluxe.Base
} }
while (line.NoteCount > n && n >= 0) 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].PointsGoldenNotes -= line.Notes[n].Points;
Players[p].Points -= line.Notes[n].Points; Players[p].Points -= line.Notes[n].Points;
line.DeleteNote(n); line.DeleteNote(n);
@@ -406,9 +406,9 @@ namespace Vocaluxe.Base
} }
Players[p].SungLines.RemoveRange(deleteLine, Players[p].SungLines.Count - deleteLine); Players[p].SungLines.RemoveRange(deleteLine, Players[p].SungLines.Count - deleteLine);
} }
CSong song = GetSong(); //CSong song = GetSong();
for (int i = 0; i < GetSong().Notes.Voices[0].Lines.Length; i++) //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); // CLog.LogError((i + 1) + ". " + song.Notes.Voices[0].Lines[i].NoteCount + " - " + Players[0].SungLines[i].NoteCount);
CSound.SetPosition(soundStream, time); CSound.SetPosition(soundStream, time);
CVideo.Skip(vidStream, time, GetSong().VideoGap); CVideo.Skip(vidStream, time, GetSong().VideoGap);
+1 -2
View File
@@ -117,8 +117,7 @@ namespace Vocaluxe.Base
MessageBox.Show(errorText, CSettings.ProgramName, MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(errorText, CSettings.ProgramName, MessageBoxButtons.OK, MessageBoxIcon.Error);
if (e != null) if (e != null)
errorText += ": " + e; errorText += ": " + e;
_ErrorLog.Add(_NumErrors + ") " + errorText + "\r\n"); _ErrorLog.Add(_NumErrors + ") " + errorText);
_ErrorLog.Add(String.Empty);
if (exit) if (exit)
Environment.Exit(Environment.ExitCode); Environment.Exit(Environment.ExitCode);
} }
+11 -1
View File
@@ -60,6 +60,11 @@ namespace Vocaluxe.Base
class CBconfig : IConfig class CBconfig : IConfig
{ {
public EOffOn GetSaveModifiedSongs()
{
return CConfig.SaveModifiedSongs;
}
public void SetBackgroundMusicVolume(int newVolume) public void SetBackgroundMusicVolume(int newVolume)
{ {
CConfig.BackgroundMusicVolume = newVolume; CConfig.BackgroundMusicVolume = newVolume;
@@ -110,7 +115,7 @@ namespace Vocaluxe.Base
return CConfig.CoverSize; return CConfig.CoverSize;
} }
public IEnumerable<string> GetSongFolder() public IEnumerable<string> GetSongFolders()
{ {
return CConfig.SongFolder; return CConfig.SongFolder;
} }
@@ -527,6 +532,11 @@ namespace Vocaluxe.Base
return CGame.GetTimeFromBeats(beat, bpm); 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) public void AddSong(int songID, EGameMode gameMode)
{ {
CGame.AddSong(songID, gameMode); CGame.AddSong(songID, gameMode);
+3 -3
View File
@@ -157,10 +157,10 @@ namespace Vocaluxe.Base
switch (_SongSorting) switch (_SongSorting)
{ {
case ESongSorting.TR_CONFIG_EDITION: case ESongSorting.TR_CONFIG_EDITION:
fieldName = "Edition"; fieldName = "Editions";
break; break;
case ESongSorting.TR_CONFIG_GENRE: case ESongSorting.TR_CONFIG_GENRE:
fieldName = "Genre"; fieldName = "Genres";
break; break;
case ESongSorting.TR_CONFIG_FOLDER: case ESongSorting.TR_CONFIG_FOLDER:
fieldName = "FolderName"; fieldName = "FolderName";
@@ -177,7 +177,7 @@ namespace Vocaluxe.Base
fieldName = "Year"; fieldName = "Year";
break; break;
case ESongSorting.TR_CONFIG_LANGUAGE: case ESongSorting.TR_CONFIG_LANGUAGE:
fieldName = "Language"; fieldName = "Languages";
break; break;
case ESongSorting.TR_CONFIG_DATEADDED: case ESongSorting.TR_CONFIG_DATEADDED:
fieldName = "DateAdded"; fieldName = "DateAdded";
+1 -1
View File
@@ -312,7 +312,7 @@ namespace Vocaluxe.Base
if (song == null) if (song == null)
continue; continue;
song.ID = _Songs.Count; song.ID = _Songs.Count;
if (song.ReadNotes()) if (song.LoadNotes())
_Songs.Add(song); _Songs.Add(song);
} }
CLog.StopBenchmark(2, "Read TXTs"); CLog.StopBenchmark(2, "Read TXTs");
+8 -4
View File
@@ -52,7 +52,7 @@ namespace Vocaluxe.GameModes
{ {
protected override CSong _PrepareSong(CSong song) 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) 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) 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 // 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; return newSong;
} }
@@ -80,6 +82,8 @@ namespace Vocaluxe.GameModes
{ {
protected override CSong _PrepareSong(CSong song) 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}; var newSong = new CSong(song) {Start = CGame.GetTimeFromBeats(song.Medley.StartBeat, song.BPM) - song.Medley.FadeInTime + song.Gap};
if (newSong.Start < 0f) if (newSong.Start < 0f)
newSong.Start = 0f; newSong.Start = 0f;
+5 -1
View File
@@ -180,7 +180,11 @@ namespace Vocaluxe.Lib.Playlist
public void AddSong(int songID) 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); Songs.Add(song);
} }
@@ -200,7 +200,7 @@ namespace Vocaluxe.Screens
CGame.ClearSongs(); CGame.ClearSongs();
var gm = EGameMode.TR_GAMEMODE_NORMAL; 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; gm = EGameMode.TR_GAMEMODE_DUET;
CGame.AddSong(songNr, gm); CGame.AddSong(songNr, gm);
+6 -2
View File
@@ -22,6 +22,7 @@ using Vocaluxe.Base;
using VocaluxeLib; using VocaluxeLib;
using VocaluxeLib.Draw; using VocaluxeLib.Draw;
using VocaluxeLib.Menu; using VocaluxeLib.Menu;
using VocaluxeLib.Songs;
namespace Vocaluxe.Screens namespace Vocaluxe.Screens
{ {
@@ -597,6 +598,8 @@ namespace Vocaluxe.Screens
_CheckMics(); _CheckMics();
_CheckPlayers(); _CheckPlayers();
CSong firstSong = CGame.GetSong(0);
for (int i = 0; i < CSettings.MaxNumPlayer; i++) for (int i = 0; i < CSettings.MaxNumPlayer; i++)
{ {
_Statics[_StaticPlayerAvatar[i]].Texture = CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID) ? _Statics[_StaticPlayerAvatar[i]].Texture = CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID) ?
@@ -607,8 +610,9 @@ namespace Vocaluxe.Screens
{ {
_SelectSlides[_SelectSlideDuetPlayer[i]].Clear(); _SelectSlides[_SelectSlideDuetPlayer[i]].Clear();
_SelectSlides[_SelectSlideDuetPlayer[i]].Visible = i + 1 <= CGame.NumPlayer; _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; _SelectSlides[_SelectSlideDuetPlayer[i]].Selection = i % 2;
} }
else else
+2 -4
View File
@@ -297,10 +297,8 @@ namespace Vocaluxe.Screens
string name = CProfiles.GetPlayerName(players[p].ProfileID, p); string name = CProfiles.GetPlayerName(players[p].ProfileID, p);
if (song != null && song.IsDuet) if (song != null && song.IsDuet)
{ {
if (players[p].VoiceNr == 0 && song.DuetPart1 != "Part 1") if (song.Notes.VoiceNames.IsSet(players[p].VoiceNr))
name += " (" + song.DuetPart1 + ")"; name += " (" + song.Notes.VoiceNames[players[p].VoiceNr] + ")";
else if (players[p].VoiceNr == 1 && song.DuetPart2 != "Part 2")
name += " (" + song.DuetPart2 + ")";
} }
_Texts[_TextNames[p, CGame.NumPlayer - 1]].Text = name; _Texts[_TextNames[p, CGame.NumPlayer - 1]].Text = name;
+65 -67
View File
@@ -327,7 +327,7 @@ namespace Vocaluxe.Screens
_LoadNextSong(); _LoadNextSong();
_UpdateSongText(); _UpdateSongText();
_UpdateDuetText(); _UpdateDuetNames();
if (_FadeOut) if (_FadeOut)
return true; return true;
@@ -387,12 +387,8 @@ namespace Vocaluxe.Screens
for (int p = 0; p < CGame.NumPlayer; p++) for (int p = 0; p < CGame.NumPlayer; p++)
{ {
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression string fmtString = (CGame.Players[p].Points < 10000) ? "0000" : "00000";
if (CGame.Players[p].Points < 10000) _Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString(fmtString);
// 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");
} }
if (_CurrentVideo != -1 && !_FadeOut && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON) if (_CurrentVideo != -1 && !_FadeOut && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON)
@@ -607,12 +603,12 @@ namespace Vocaluxe.Screens
_FinishTime = song.Finish; _FinishTime = song.Finish;
_TimeToFirstNote = 0f; _TimeToFirstNote = 0f;
_TimeToFirstNoteDuet = 0f; _TimeToFirstNoteDuet = 0f;
var duetPlayer = new int[CGame.NumPlayer]; var voiceAssignments = new int[CGame.NumPlayer];
if (song.IsDuet) if (song.IsDuet)
{ {
//Save duet-assignment before resetting //Save duet-assignment before resetting
for (int i = 0; i < duetPlayer.Length; i++) for (int i = 0; i < voiceAssignments.Length; i++)
duetPlayer[i] = CGame.Players[i].VoiceNr; voiceAssignments[i] = CGame.Players[i].VoiceNr;
} }
CGame.ResetPlayer(); CGame.ResetPlayer();
@@ -634,8 +630,9 @@ namespace Vocaluxe.Screens
if (song.IsDuet) if (song.IsDuet)
{ {
_Texts[_TextDuetName1].Text = song.DuetPart1; //TODO: Show more than 2 voicenames
_Texts[_TextDuetName2].Text = song.DuetPart2; _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 //More than one song: Player is not assigned to line by user
//Otherwise, this is done by CScreenNames //Otherwise, this is done by CScreenNames
if (CGame.GetNumSongs() > 1) if (CGame.GetNumSongs() > 1)
@@ -646,7 +643,7 @@ namespace Vocaluxe.Screens
else else
{ {
for (int i = 0; i < CGame.NumPlayer; i++) 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]); NoteLines[3] = SingNotes[SingBars].AddPlayer(new SRectF(640f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[3]);
break; break;
*/ */
_TimerSongText.Stop();
_TimerSongText.Reset(); _TimerSongText.Reset();
_TimerDuetText1.Stop();
_TimerDuetText1.Reset(); _TimerDuetText1.Reset();
_TimerDuetText2.Stop();
_TimerDuetText2.Reset(); _TimerDuetText2.Reset();
if (song.Notes.Voices.Length != 2) if (!song.IsDuet)
_TimerSongText.Start(); _TimerSongText.Start();
_StartSong(); _StartSong();
@@ -781,7 +775,7 @@ namespace Vocaluxe.Screens
_CurrentBeat = CGame.CurrentBeat; _CurrentBeat = CGame.CurrentBeat;
for (int i = 0; i < song.Notes.LinesCount; i++) for (int i = 0; i < song.Notes.VoiceCount; i++)
{ {
if (i > 1) if (i > 1)
break; // for later break; // for later
@@ -1090,10 +1084,10 @@ namespace Vocaluxe.Screens
if (song == null || !song.NotesLoaded) if (song == null || !song.NotesLoaded)
return null; return null;
var alpha = new float[song.Notes.Voices.Length * 2]; var alpha = new float[song.Notes.VoiceCount * 2];
float currentTime = _CurrentTime - song.Gap; 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); CVoice voice = song.Notes.GetVoice(i);
CSongLine[] lines = voice.Lines; CSongLine[] lines = voice.Lines;
@@ -1197,8 +1191,8 @@ namespace Vocaluxe.Screens
} }
else else
{ {
_Statics[_StaticSongText].Color.A = (3f - (t - 7f)) / 3f; _Statics[_StaticSongText].Color.A = 10f - t / 3f;
_Texts[_TextSongName].Color.A = (3f - (t - 7f)) / 3f; _Texts[_TextSongName].Color.A = 10f - t / 3f;
} }
} }
else 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 float t = timer.ElapsedMilliseconds / 1000f;
if (_TimerDuetText1.IsRunning) if (t < 10f)
{ {
float t = _TimerDuetText1.ElapsedMilliseconds / 1000f; textName.Visible = true;
if (t < 10f)
{
_Texts[_TextDuetName1].Visible = true;
if (t < 3f) if (t < 3f)
_Texts[_TextDuetName1].Color.A = (3f - (3f - t)) / 3f; textName.Color.A = t / 3f;
else if (t < 7f) else if (t < 7f)
_Texts[_TextDuetName1].Color.A = 1f; textName.Color.A = 1f;
else
_Texts[_TextDuetName1].Color.A = (3f - (t - 7f)) / 3f;
}
else else
{ textName.Color.A = (10f - t) / 3f;
_Texts[_TextDuetName1].Visible = false;
_TimerDuetText1.Stop();
}
} }
else if (!_TimerDuetText1.IsRunning && _TimerDuetText1.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet)
_TimerDuetText1.Start();
else else
_Texts[_TextDuetName1].Visible = false;
//Timer for second duet-part
if (_TimerDuetText2.IsRunning)
{ {
float t = _TimerDuetText2.ElapsedMilliseconds / 1000f; textName.Visible = false;
if (t < 10f) timer.Stop();
{
_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;
} }
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() private void _UpdateTimeLine()
+21 -27
View File
@@ -819,9 +819,8 @@ namespace Vocaluxe.Screens
CGame.Reset(); CGame.Reset();
CGame.ClearSongs(); CGame.ClearSongs();
CGame.AddVisibleSong(songNr, gm); if (CGame.AddVisibleSong(songNr, gm))
CGraphics.FadeTo(EScreens.ScreenNames);
CGraphics.FadeTo(EScreens.ScreenNames);
} }
} }
@@ -834,9 +833,8 @@ namespace Vocaluxe.Screens
CGame.Reset(); CGame.Reset();
CGame.ClearSongs(); CGame.ClearSongs();
CGame.AddVisibleSong(songNr, gm); if (CGame.AddVisibleSong(songNr, gm))
CGraphics.FadeTo(EScreens.ScreenNames);
CGraphics.FadeTo(EScreens.ScreenNames);
} }
} }
@@ -844,14 +842,13 @@ namespace Vocaluxe.Screens
{ {
if ((CSongs.Category >= 0) && (songNr >= 0)) if ((CSongs.Category >= 0) && (songNr >= 0))
{ {
if (CSongs.VisibleSongs[songNr].Medley.Source == EMedleySource.None) if (!CSongs.VisibleSongs[songNr].IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
return; return;
CGame.Reset(); CGame.Reset();
CGame.ClearSongs(); CGame.ClearSongs();
CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY); if (CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY))
CGraphics.FadeTo(EScreens.ScreenNames);
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() private void _ShowSongOptionsSong()
{ {
var lastMode = EGameMode.TR_GAMEMODE_NORMAL; var lastMode = EGameMode.TR_GAMEMODE_NORMAL;
@@ -1172,23 +1178,11 @@ namespace Vocaluxe.Screens
lastMode = _AvailableGameModes[_SelectSlides[_SelectSlideOptionsMode].Selection]; lastMode = _AvailableGameModes[_SelectSlides[_SelectSlideOptionsMode].Selection];
_AvailableGameModes.Clear(); _AvailableGameModes.Clear();
_SelectSlides[_SelectSlideOptionsMode].Clear(); _SelectSlides[_SelectSlideOptionsMode].Clear();
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].IsDuet) _CheckAndAddGameMode(EGameMode.TR_GAMEMODE_NORMAL);
{ _CheckAndAddGameMode(EGameMode.TR_GAMEMODE_DUET);
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_DUET)); _CheckAndAddGameMode(EGameMode.TR_GAMEMODE_SHORTSONG);
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_DUET); _CheckAndAddGameMode(EGameMode.TR_GAMEMODE_MEDLEY);
}
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);
}
//Set SelectSlide-Selection to last selected game-mode if possible //Set SelectSlide-Selection to last selected game-mode if possible
for (int i = 0; i < _AvailableGameModes.Count; i++) for (int i = 0; i < _AvailableGameModes.Count; i++)
{ {
+1 -1
View File
@@ -69,7 +69,7 @@ namespace Vocaluxe.SongQueue
private bool _AddSong(int songID, EGameMode gameMode) 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; return false;
_SongQueue.Add(new SSongQueueEntry(songID, gameMode)); _SongQueue.Add(new SSongQueueEntry(songID, gameMode));
+4 -11
View File
@@ -53,7 +53,6 @@ namespace VocaluxeLib
public static string ListStrings(string[] str) public static string ListStrings(string[] str)
{ {
string result = string.Empty; string result = string.Empty;
for (int i = 0; i < str.Length; i++) for (int i = 0; i < str.Length; i++)
{ {
result += str[i]; result += str[i];
@@ -160,13 +159,7 @@ namespace VocaluxeLib
return files; return files;
} }
public static bool TryParse<T>(string value, out T result) public static bool TryParse<T>(string value, out T result, bool ignoreCase=false)
where T : struct
{
return TryParse(value, out result, false);
}
public static bool TryParse<T>(string value, out T result, bool ignoreCase)
where T : struct where T : struct
{ {
result = default(T); result = default(T);
@@ -199,7 +192,7 @@ namespace VocaluxeLib
static class CEncoding static class CEncoding
{ {
public static Encoding GetEncoding(string encodingName) public static Encoding GetEncoding(this string encodingName)
{ {
switch (encodingName) switch (encodingName)
{ {
@@ -214,11 +207,11 @@ namespace VocaluxeLib
case "UTF8": case "UTF8":
return Encoding.UTF8; return Encoding.UTF8;
default: default:
return Encoding.UTF8; return Encoding.Default;
} }
} }
public static string GetEncodingName(Encoding enc) public static string GetEncodingName(this Encoding enc)
{ {
string result = "UTF8"; string result = "UTF8";
+112
View File
@@ -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);
}
}
}
+4 -1
View File
@@ -29,6 +29,8 @@ namespace VocaluxeLib
{ {
public interface IConfig public interface IConfig
{ {
EOffOn GetSaveModifiedSongs();
void SetBackgroundMusicVolume(int newVolume); void SetBackgroundMusicVolume(int newVolume);
int GetBackgroundMusicVolume(); int GetBackgroundMusicVolume();
@@ -45,7 +47,7 @@ namespace VocaluxeLib
int GetCoverSize(); int GetCoverSize();
IEnumerable<string> GetSongFolder(); IEnumerable<string> GetSongFolders();
ESongSorting GetSongSorting(); ESongSorting GetSongSorting();
EOffOn GetTabs(); EOffOn GetTabs();
EOffOn GetIgnoreArticles(); EOffOn GetIgnoreArticles();
@@ -179,6 +181,7 @@ namespace VocaluxeLib
double GetRandomDouble(); double GetRandomDouble();
float GetTimeFromBeats(float beat, float bpm); float GetTimeFromBeats(float beat, float bpm);
float GetBeatFromTime(float time, float bpm, float gap);
void AddSong(int songID, EGameMode gameMode); void AddSong(int songID, EGameMode gameMode);
void Reset(); void Reset();
+55 -108
View File
@@ -23,15 +23,6 @@ using VocaluxeLib.Songs;
namespace VocaluxeLib.Menu namespace VocaluxeLib.Menu
{ {
struct SNote
{
public string Text;
public int StartBeat;
public int EndBeat;
public int Duration;
public ENoteType Type;
}
struct SThemeLyrics struct SThemeLyrics
{ {
public string Name; public string Name;
@@ -46,7 +37,10 @@ namespace VocaluxeLib.Menu
private SThemeLyrics _Theme; private SThemeLyrics _Theme;
private bool _ThemeLoaded; 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 CText _Text;
private float _X; private float _X;
@@ -109,7 +103,7 @@ namespace VocaluxeLib.Menu
_MaxW = 1f; _MaxW = 1f;
_H = 1f; _H = 1f;
_Width = 1f; _Width = 1f;
_Notes = new List<SNote>(); _Line = new CSongLine();
_Text = new CText(_PartyModeID); _Text = new CText(_PartyModeID);
LyricStyle = ELyricStyle.Fill; LyricStyle = ELyricStyle.Fill;
@@ -201,28 +195,27 @@ namespace VocaluxeLib.Menu
public void SetLine(CSongLine line) public void SetLine(CSongLine line)
{ {
_Notes.Clear(); _Line = line;
_Width = 0f; _Width = 0f;
foreach (CSongNote note in line.Notes) 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}; _SetText(note);
_Width += _Text.Rect.W;
_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);
} }
} }
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() public void Clear()
{ {
_Notes.Clear(); _Line = new CSongLine();
} }
public float GetCurrentLyricPosX() public float GetCurrentLyricPosX()
@@ -260,15 +253,10 @@ namespace VocaluxeLib.Menu
{ {
float x = _X - _Width / 2; float x = _X - _Width / 2;
foreach (SNote note in _Notes) foreach (CSongNote note in _Line.Notes)
{ {
_Text.X = x; _Text.X = x;
_Text.Style = EStyle.Bold; _SetText(note);
_Text.Text = note.Text;
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
if (note.Type == ENoteType.Freestyle)
_Text.Style = EStyle.BoldItalic;
if (currentBeat >= note.StartBeat) if (currentBeat >= note.StartBeat)
{ {
@@ -276,9 +264,8 @@ namespace VocaluxeLib.Menu
{ {
_Text.Color = _ColorProcessed; _Text.Color = _ColorProcessed;
int diff = note.EndBeat - note.StartBeat;
float diff = note.EndBeat - note.StartBeat; if (diff <= 0)
if (Math.Abs(diff) < float.Epsilon)
_Text.Draw(0f, 1f); _Text.Draw(0f, 1f);
else else
{ {
@@ -299,7 +286,7 @@ namespace VocaluxeLib.Menu
_Text.Draw(); _Text.Draw();
} }
x += rect.Width; x += _Text.Rect.W;
} }
} }
@@ -308,37 +295,27 @@ namespace VocaluxeLib.Menu
float x = _X - _Width / 2; // most left position float x = _X - _Width / 2; // most left position
//find last active note //find last active note
int lastNote = -1; int lastNote = _Line.FindPreviousNote((int)currentBeat);
for (int i = 0; i < _Notes.Count; i++)
{
if (currentBeat >= _Notes[i].StartBeat)
lastNote = i;
}
int zoomNote = -1; int zoomNote = -1;
int endBeat = -1; int endBeat = -1;
float zoomx = 0f; float zoomx = 0f;
for (int note = 0; note < _Notes.Count; note++) for (int note = 0; note < _Line.Notes.Length; note++)
{ {
_Text.X = x; _Text.X = x;
_Text.Style = EStyle.Bold; _SetText(_Line.Notes[note]);
_Text.Text = _Notes[note].Text;
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
if (_Notes[note].Type == ENoteType.Freestyle) if (currentBeat >= _Line.Notes[note].StartBeat)
_Text.Style = EStyle.BoldItalic;
if (currentBeat >= _Notes[note].StartBeat)
{ {
int endbeat = _Notes[note].EndBeat; int curEndBeat = _Line.Notes[note].EndBeat;
if (note < _Notes.Count - 1) if (note < _Line.Notes.Length - 1)
endbeat = _Notes[note + 1].StartBeat - 1; curEndBeat = _Line.Notes[note + 1].StartBeat - 1;
if (currentBeat <= endbeat) if (currentBeat <= curEndBeat)
{ {
zoomNote = note; zoomNote = note;
endBeat = endbeat; endBeat = curEndBeat;
zoomx = _Text.X; zoomx = _Text.X;
} }
else else
@@ -356,49 +333,37 @@ namespace VocaluxeLib.Menu
_Text.Draw(); _Text.Draw();
} }
x += rect.Width; x += _Text.Rect.W;
} }
if (zoomNote > -1) if (zoomNote > -1)
{ {
if (_Notes[zoomNote].Duration == 0)
return;
_Text.X = zoomx; _Text.X = zoomx;
_Text.Text = _Notes[zoomNote].Text; _SetText(_Line.Notes[zoomNote]);
_Text.Color = _ColorProcessed;
_Text.Style = EStyle.Bold;
if (_Notes[zoomNote].Type == ENoteType.Freestyle) float diff = endBeat - _Line.Notes[zoomNote].StartBeat;
_Text.Style = EStyle.BoldItalic;
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
float diff = endBeat - _Notes[zoomNote].StartBeat;
if (diff <= 0f) if (diff <= 0f)
diff = 1f; diff = 1f;
float p = (currentBeat - _Notes[zoomNote].StartBeat) / diff; float p = (currentBeat - _Line.Notes[zoomNote].StartBeat) / diff;
if (p > 1f) if (p > 1f)
p = 1f; p = 1f;
p = 1f - p; p = 1f - p;
float ty = _Text.Y; float ty = _Text.Y;
float tx = _Text.X;
float th = _Text.Height; float th = _Text.Height;
float tz = _Text.Z; float tz = _Text.Z;
SRectF normalRect = _Text.Rect;
_Text.Height += _Text.Height * p * 0.4f; _Text.Height += _Text.Height * p * 0.4f;
RectangleF rectz = CBase.Fonts.GetTextBounds(_Text); _Text.X -= (_Text.Rect.W - normalRect.W) / 2f;
_Text.X -= (rectz.Width - rect.Width) / 2f; _Text.Y -= (_Text.Rect.W - normalRect.H) / 2f;
_Text.Y -= (rectz.Height - rect.Height) / 2f;
_Text.Z -= 0.1f; _Text.Z -= 0.1f;
_Text.Draw(); _Text.Draw();
_Text.Y = ty; _Text.Y = ty;
_Text.X = tx;
_Text.Height = th; _Text.Height = th;
_Text.Z = tz; _Text.Z = tz;
} }
@@ -408,15 +373,10 @@ namespace VocaluxeLib.Menu
{ {
float x = _X - _Width / 2; // most left position float x = _X - _Width / 2; // most left position
foreach (SNote note in _Notes) foreach (CSongNote note in _Line.Notes)
{ {
_Text.X = x; _Text.X = x;
_Text.Style = EStyle.Bold; _SetText(note);
_Text.Text = note.Text;
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
if (note.Type == ENoteType.Freestyle)
_Text.Style = EStyle.BoldItalic;
if (currentBeat >= note.StartBeat) if (currentBeat >= note.StartBeat)
{ {
@@ -430,7 +390,7 @@ namespace VocaluxeLib.Menu
_Text.Draw(); _Text.Draw();
} }
x += rect.Width; x += _Text.Rect.W;
} }
} }
@@ -439,29 +399,23 @@ namespace VocaluxeLib.Menu
float x = _X - _Width / 2; // most left position float x = _X - _Width / 2; // most left position
//find last active note //find last active note
int lastNote = -1; int lastNote = _Line.FindPreviousNote((int)currentBeat);
for (int i = 0; i < _Notes.Count; i++)
{
if (currentBeat >= _Notes[i].StartBeat)
lastNote = i;
}
int jumpNote = -1; int jumpNote = -1;
float jumpx = 0f; float jumpx = 0f;
for (int note = 0; note < _Notes.Count; note++) for (int note = 0; note < _Line.Notes.Length; note++)
{ {
_Text.X = x; _Text.X = x;
_Text.Style = EStyle.Bold; _SetText(_Line.Notes[note]);
_Text.Text = _Notes[note].Text;
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
if (_Notes[note].Type == ENoteType.Freestyle) if (currentBeat >= _Line.Notes[note].StartBeat)
_Text.Style = EStyle.BoldItalic;
if (currentBeat >= _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; jumpNote = note;
jumpx = _Text.X; jumpx = _Text.X;
@@ -481,27 +435,20 @@ namespace VocaluxeLib.Menu
_Text.Draw(); _Text.Draw();
} }
x += rect.Width; x += _Text.Rect.W;
} }
if (jumpNote < 0) if (jumpNote < 0)
return; return;
if (_Notes[jumpNote].Duration == 0)
return;
_Text.X = jumpx; _Text.X = jumpx;
_Text.Text = _Notes[jumpNote].Text; _SetText(_Line.Notes[jumpNote]);
_Text.Color = _ColorProcessed;
_Text.Style = EStyle.Bold;
if (_Notes[jumpNote].Type == ENoteType.Freestyle) int diff = _Line.Notes[jumpNote].EndBeat - _Line.Notes[jumpNote].StartBeat;
_Text.Style = EStyle.BoldItalic;
int diff = _Notes[jumpNote].EndBeat - _Notes[jumpNote].StartBeat;
if (diff <= 0) if (diff <= 0)
diff = 1; 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) if (Math.Abs(p) < float.Epsilon)
_Text.Draw(); _Text.Draw();
+3 -3
View File
@@ -84,7 +84,7 @@ namespace VocaluxeLib.Menu
{ {
private class CPlaylistElementContent private class CPlaylistElementContent
{ {
public EGameMode[] Modes; public IList<EGameMode> Modes;
public int SongID; public int SongID;
public EGameMode Mode; public EGameMode Mode;
} }
@@ -971,11 +971,11 @@ namespace VocaluxeLib.Menu
if (!mouseEvent.LBH && DragAndDropSongID != -1) if (!mouseEvent.LBH && DragAndDropSongID != -1)
{ {
var gm = EGameMode.TR_GAMEMODE_NORMAL;
CSong song = CBase.Songs.GetSongByID(DragAndDropSongID); CSong song = CBase.Songs.GetSongByID(DragAndDropSongID);
if (song != null) if (song != null)
{ {
var gm = EGameMode.TR_GAMEMODE_NORMAL;
if (song.IsDuet) if (song.IsDuet)
gm = EGameMode.TR_GAMEMODE_DUET; 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); 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].Text1.Text = /*(Offset + i + 1) + ") " + */ t1; //TODO: Add text field for the number
_PlaylistElements[i].SelectSlide.Clear(); _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])); _PlaylistElements[i].SelectSlide.AddValue(Enum.GetName(typeof(EGameMode), pec.Modes[g]));
if (pec.Modes[g] == pec.Mode) if (pec.Modes[g] == pec.Mode)
+1 -1
View File
@@ -561,7 +561,7 @@ namespace VocaluxeLib.Menu
float y = Y; float y = Y;
RectangleF bounds = CBase.Fonts.GetTextBounds(this); 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 factor = MaxWidth / bounds.Width;
float step = h * (1 - factor); float step = h * (1 - factor);
+3 -3
View File
@@ -319,7 +319,7 @@ namespace VocaluxeLib.Menu.SingNotes
int nr = 1; int nr = 1;
foreach (CSongNote note in line.Notes) foreach (CSongNote note in line.Notes)
{ {
if (note.NoteType != ENoteType.Freestyle) if (note.Type != ENoteType.Freestyle)
{ {
float width = note.Duration / beats * w; float width = note.Duration / beats * w;
@@ -334,7 +334,7 @@ namespace VocaluxeLib.Menu.SingNotes
_DrawNoteBG(rect, color, 1f, _PlayerNotes[n].Timer); _DrawNoteBG(rect, color, 1f, _PlayerNotes[n].Timer);
_DrawNote(rect, new SColorF(5f, 5f, 5f, 0.7f * _PlayerNotes[n].Alpha), 0.7f); _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); _AddGoldenNote(rect, n, nr);
nr++; nr++;
@@ -386,7 +386,7 @@ namespace VocaluxeLib.Menu.SingNotes
_DrawNote(rect, color, f); _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}; var re = new SRectF(rect) {W = (CBase.Game.GetMidRecordedBeat() - note.StartBeat) / beats * w};
_AddFlare(re, n); _AddFlare(re, n);
+16 -14
View File
@@ -22,6 +22,7 @@ using System.IO;
using System.Xml; using System.Xml;
using VocaluxeLib.Draw; using VocaluxeLib.Draw;
using VocaluxeLib.PartyModes; using VocaluxeLib.PartyModes;
using VocaluxeLib.Songs;
namespace VocaluxeLib.Menu.SongMenu namespace VocaluxeLib.Menu.SongMenu
{ {
@@ -101,7 +102,7 @@ namespace VocaluxeLib.Menu.SongMenu
private readonly Stopwatch _Timer = new Stopwatch(); private readonly Stopwatch _Timer = new Stopwatch();
private readonly Stopwatch _VideoFadeTimer = new Stopwatch(); private readonly Stopwatch _VideoFadeTimer = new Stopwatch();
private readonly List<int> _Streams = new List<int>(); private readonly List<int> _Streams = new List<int>();
private int _Actsong = -1; private int _ActSongId = -1;
private int _Actsongstream = -1; private int _Actsongstream = -1;
protected CTexture _Vidtex; protected CTexture _Vidtex;
@@ -186,7 +187,7 @@ namespace VocaluxeLib.Menu.SongMenu
protected int _ActSong protected int _ActSong
{ {
get { return _Actsong; } get { return _ActSongId; }
} }
public SRectF Rect public SRectF Rect
@@ -206,7 +207,7 @@ namespace VocaluxeLib.Menu.SongMenu
public virtual int GetActualSelection() public virtual int GetActualSelection()
{ {
return _Actsong; return _ActSongId;
} }
private bool _Selected; private bool _Selected;
@@ -434,7 +435,7 @@ namespace VocaluxeLib.Menu.SongMenu
if (!_Initialized) if (!_Initialized)
return; return;
if (_Actsong != _PreviewSelected) if (_ActSongId != _PreviewSelected)
_SelectSong(_PreviewSelected); _SelectSong(_PreviewSelected);
if (_Streams.Count <= 0 || _Video == -1) if (_Streams.Count <= 0 || _Video == -1)
@@ -607,7 +608,7 @@ namespace VocaluxeLib.Menu.SongMenu
protected void _SelectSong(int nr) 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.ForEach(soundStream => CBase.Sound.FadeAndStop(soundStream, 0f, 1f));
_Streams.Clear(); _Streams.Clear();
@@ -617,18 +618,19 @@ namespace VocaluxeLib.Menu.SongMenu
CBase.Drawing.RemoveTexture(ref _Vidtex); CBase.Drawing.RemoveTexture(ref _Vidtex);
_Actsong = nr; _ActSongId = nr;
if (_Actsong >= CBase.Songs.GetNumSongsVisible()) if (_ActSongId >= CBase.Songs.GetNumSongsVisible())
_Actsong = 0; _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.SetStreamVolumeMax(stream, _MaxVolume);
CBase.Sound.SetStreamVolume(stream, 0f); 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; startposition = CBase.Sound.GetLength(stream) / 4f;
if (startposition >= 0.5f) if (startposition >= 0.5f)
@@ -640,12 +642,12 @@ namespace VocaluxeLib.Menu.SongMenu
_Streams.Add(stream); _Streams.Add(stream);
_Actsongstream = 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) if (_Video == -1)
return; return;
CBase.Video.Skip(_Video, startposition, CBase.Songs.GetVisibleSong(_Actsong).VideoGap); CBase.Video.Skip(_Video, startposition, actSong.VideoGap);
_VideoFadeTimer.Stop(); _VideoFadeTimer.Stop();
_VideoFadeTimer.Reset(); _VideoFadeTimer.Reset();
_VideoFadeTimer.Start(); _VideoFadeTimer.Start();
@@ -413,8 +413,8 @@ namespace VocaluxeLib.Menu.SongMenu
_Title.Text = song.Title; _Title.Text = song.Title;
_DuetIcon.Visible = song.IsDuet; _DuetIcon.Visible = song.IsDuet;
_VideoIcon.Visible = song.VideoFileName != ""; _VideoIcon.Visible = song.VideoFileName != "";
_MedleyCalcIcon.Visible = song.Medley.Source == EMedleySource.Calculated; _MedleyCalcIcon.Visible = song.Medley.Source == EDataSource.Calculated;
_MedleyTagIcon.Visible = song.Medley.Source == EMedleySource.Tag; _MedleyTagIcon.Visible = song.Medley.Source == EDataSource.Tag;
float time = CBase.Sound.GetLength(_SongStream); float time = CBase.Sound.GetLength(_SongStream);
if (Math.Abs(song.Finish) > 0.001) if (Math.Abs(song.Finish) > 0.001)
+7
View File
@@ -15,6 +15,8 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>. // along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion #endregion
using System;
namespace VocaluxeLib.Songs namespace VocaluxeLib.Songs
{ {
/// <summary> /// <summary>
@@ -38,12 +40,17 @@ namespace VocaluxeLib.Songs
StartBeat = startBeat; StartBeat = startBeat;
Duration = duration; Duration = duration;
Tone = tone; Tone = tone;
if (Duration < 1)
throw new Exception("Note to short. All notes should be at least 1 beat long!");
} }
#endregion Constructors #endregion Constructors
#region Properties #region Properties
public int StartBeat { get; set; } 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 public int EndBeat
{ {
get { return StartBeat + _Duration - 1; } get { return StartBeat + _Duration - 1; }
+5 -1
View File
@@ -79,7 +79,11 @@ namespace VocaluxeLib.Songs
#endregion Properties #endregion Properties
#region Methods #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) public int FindPreviousNote(int beat)
{ {
//If no notes -> No previous note //If no notes -> No previous note
+51 -10
View File
@@ -21,24 +21,63 @@ namespace VocaluxeLib.Songs
{ {
public class CNotes public class CNotes
{ {
private readonly List<CVoice> _Voices = new List<CVoice>(); public class CVoiceNames
public CVoice[] Voices
{ {
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 CNotes() {}
public int LinesCount
{
get { return _Voices.Count; }
}
public CNotes(CNotes notes) public CNotes(CNotes notes)
{ {
foreach (CVoice voice in notes._Voices) foreach (CVoice voice in notes._Voices)
_Voices.Add(new CVoice(voice)); _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) public CVoice GetVoice(int index)
@@ -79,9 +118,11 @@ namespace VocaluxeLib.Songs
return true; return true;
} }
public void Reset() public void Reset(bool resetVoices = false)
{ {
_Voices.Clear(); _Voices.Clear();
if (resetVoices)
VoiceNames.Reset();
} }
public void SetMedley(int startBeat, int endBeat) public void SetMedley(int startBeat, int endBeat)
+126 -574
View File
@@ -20,7 +20,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using VocaluxeLib.Draw; using VocaluxeLib.Draw;
namespace VocaluxeLib.Songs namespace VocaluxeLib.Songs
@@ -45,12 +44,11 @@ namespace VocaluxeLib.Songs
Artist = 2, Artist = 2,
MP3 = 4, MP3 = 4,
BPM = 8, BPM = 8,
PreviewStart = 16, MedleyStartBeat = 16,
MedleyStartBeat = 32, MedleyEndBeat = 32
MedleyEndBeat = 64
} }
public enum EMedleySource public enum EDataSource
{ {
None = 0, None = 0,
Calculated, Calculated,
@@ -59,30 +57,43 @@ namespace VocaluxeLib.Songs
public struct SMedley public struct SMedley
{ {
public EMedleySource Source; public EDataSource Source;
public int StartBeat; public int StartBeat;
public int EndBeat; public int EndBeat;
public float FadeInTime; public float FadeInTime;
public float FadeOutTime; 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 _CoverTextureSmall;
private CTexture _CoverTextureBig; private CTexture _CoverTextureBig;
public SMedley Medley; public SMedley Medley;
public bool CalculateMedley = true; private bool _CalculateMedley = true;
public float PreviewStart; public SPreview Preview;
public int ShortEnd; public SShortEnd ShortEnd;
public Encoding Encoding = Encoding.Default; public Encoding Encoding = Encoding.Default;
public bool ManualEncoding;
public string Folder = String.Empty; public string Folder = String.Empty;
public string FolderName = String.Empty; public string FolderName = String.Empty;
public string FileName = String.Empty; public string FileName = String.Empty;
public EOffOn Relative = EOffOn.TR_CONFIG_OFF; public bool Relative;
public string MP3FileName = String.Empty; public string MP3FileName = String.Empty;
public string CoverFileName = String.Empty; public string CoverFileName = String.Empty;
@@ -117,17 +128,31 @@ namespace VocaluxeLib.Songs
public string TitleSorting = String.Empty; public string TitleSorting = String.Empty;
public string ArtistSorting = 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; public float Start;
/// <summary>
/// End of the song in s (ms in txt)
/// </summary>
public float Finish; public float Finish;
public float BPM = 1f; public float BPM = 1f;
/// <summary>
/// Gap of the mp3 in s (ms in txt)
/// </summary>
public float Gap; public float Gap;
/// <summary>
/// Gap of the video in s (s in txt)
/// </summary>
public float VideoGap; public float VideoGap;
public string DuetPart1 = String.Empty; private string _Comment = "";
public string DuetPart2 = String.Empty;
private readonly List<string> _Comment = new List<string>();
// Sorting // Sorting
public int ID; public int ID;
@@ -136,14 +161,15 @@ namespace VocaluxeLib.Songs
private readonly bool _Selected; private readonly bool _Selected;
public bool IsDuet 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> Editions = new List<string>();
public readonly List<string> Genre = new List<string>(); public readonly List<string> Genres = new List<string>();
public string Album = "";
public string Year = ""; public string Year = "";
public readonly List<string> Language = new List<string>(); public readonly List<string> Languages = new List<string>();
public int DataBaseSongID = -1; public int DataBaseSongID = -1;
public string DateAdded = ""; public string DateAdded = "";
@@ -152,50 +178,47 @@ namespace VocaluxeLib.Songs
// Notes // Notes
public readonly CNotes Notes = new CNotes(); public readonly CNotes Notes = new CNotes();
public EGameMode[] AvailableGameModes public IList<EGameMode> AvailableGameModes
{ {
get get
{ {
var gms = new List<EGameMode> {IsDuet ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL}; 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_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 //No point creating a song without a text file --> Use factory method LoadSong
private CSong() {} private CSong() {}
public static CSong LoadSong(string filePath)
{
var song = new CSong();
return song.ReadHeader(filePath) ? song : null;
}
public CSong(CSong song) public CSong(CSong song)
{ {
_CoverTextureSmall = song._CoverTextureSmall; _CoverTextureSmall = song._CoverTextureSmall;
_CoverTextureBig = song._CoverTextureBig; _CoverTextureBig = song._CoverTextureBig;
Medley = new SMedley Medley = song.Medley;
{
Source = song.Medley.Source,
StartBeat = song.Medley.StartBeat,
EndBeat = song.Medley.EndBeat,
FadeInTime = song.Medley.FadeInTime,
FadeOutTime = song.Medley.FadeOutTime
};
CalculateMedley = song.CalculateMedley; _CalculateMedley = song._CalculateMedley;
PreviewStart = song.PreviewStart; Preview = song.Preview;
ShortEnd = song.ShortEnd; ShortEnd = song.ShortEnd;
DuetPart1 = song.DuetPart1;
DuetPart2 = song.DuetPart2;
Encoding = song.Encoding; Encoding = song.Encoding;
ManualEncoding = song.ManualEncoding;
Folder = song.Folder; Folder = song.Folder;
FolderName = song.FolderName; FolderName = song.FolderName;
FileName = song.FileName; FileName = song.FileName;
@@ -211,6 +234,13 @@ namespace VocaluxeLib.Songs
Artist = song.Artist; Artist = song.Artist;
Title = song.Title; 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; Start = song.Start;
Finish = song.Finish; Finish = song.Finish;
@@ -219,28 +249,19 @@ namespace VocaluxeLib.Songs
Gap = song.Gap; Gap = song.Gap;
VideoGap = song.VideoGap; VideoGap = song.VideoGap;
_Comment = new List<string>(); _Comment = song._Comment;
foreach (string value in song._Comment)
_Comment.Add(value);
ID = song.ID; ID = song.ID;
_Visible = song._Visible; _Visible = song._Visible;
_CatIndex = song._CatIndex; _CatIndex = song._CatIndex;
_Selected = song._Selected; _Selected = song._Selected;
Edition = new List<string>(); Editions = new List<string>(song.Editions);
foreach (string value in song.Edition) Genres = new List<string>(song.Genres);
Edition.Add(value); Album = song.Album;
Genre = new List<string>();
foreach (string value in song.Genre)
Genre.Add(value);
Year = song.Year; Year = song.Year;
Language = new List<string>(); Languages = new List<string>(song.Languages);
foreach (string value in song.Language)
Language.Add(value);
DataBaseSongID = song.DataBaseSongID; DataBaseSongID = song.DataBaseSongID;
DateAdded = song.DateAdded; DateAdded = song.DateAdded;
@@ -249,6 +270,25 @@ namespace VocaluxeLib.Songs
Notes = new CNotes(song.Notes); 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() public string GetMP3()
{ {
return Path.Combine(Folder, MP3FileName); return Path.Combine(Folder, MP3FileName);
@@ -259,494 +299,6 @@ namespace VocaluxeLib.Songs
return Path.Combine(Folder, VideoFileName); 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() public void LoadSmallCover()
{ {
if (_CoverTextureSmall != null) if (_CoverTextureSmall != null)
@@ -765,11 +317,13 @@ namespace VocaluxeLib.Songs
if (CoverFileName == "") if (CoverFileName == "")
{ {
List<string> files = CHelper.ListFiles(Folder, "*.jpg"); List<string> files = CHelper.ListFiles(Folder, "*.jpg");
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
files.AddRange(CHelper.ListFiles(Folder, "*.png")); files.AddRange(CHelper.ListFiles(Folder, "*.png"));
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
foreach (String file in files) foreach (String file in files)
{ {
if (Regex.IsMatch(file, @".[CO].", RegexOptions.IgnoreCase) && if (file.ContainsIgnoreCase("[CO]") &&
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase))) (file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
CoverFileName = file; CoverFileName = file;
} }
} }
@@ -777,11 +331,13 @@ namespace VocaluxeLib.Songs
if (BackgroundFileName == "") if (BackgroundFileName == "")
{ {
List<string> files = CHelper.ListFiles(Folder, "*.jpg"); List<string> files = CHelper.ListFiles(Folder, "*.jpg");
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
files.AddRange(CHelper.ListFiles(Folder, "*.png")); files.AddRange(CHelper.ListFiles(Folder, "*.png"));
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
foreach (String file in files) foreach (String file in files)
{ {
if (Regex.IsMatch(file, @".[BG].", RegexOptions.IgnoreCase) && if (file.ContainsIgnoreCase("[BG]") &&
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase))) (file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
BackgroundFileName = file; BackgroundFileName = file;
} }
} }
@@ -789,15 +345,10 @@ namespace VocaluxeLib.Songs
private void _CheckDuet() private void _CheckDuet()
{ {
if (DuetPart1 == "") for (int i = 0; i < Notes.VoiceCount; i++)
{ {
DuetPart1 = "Part 1"; if (!Notes.VoiceNames.IsSet(i))
CBase.Log.LogError("Warning: Can't find #P1-tag for duets in \"" + Artist + " - " + Title + "\"."); CBase.Log.LogError("Warning: Can't find #P" + (i + 1) + "-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 + "\".");
} }
} }
@@ -853,14 +404,11 @@ namespace VocaluxeLib.Songs
{ {
if (IsDuet) if (IsDuet)
{ {
Medley.Source = EMedleySource.None; Medley.Source = EDataSource.None;
return; return;
} }
if (Medley.Source == EMedleySource.Tag) if (!_CalculateMedley)
return;
if (!CalculateMedley)
return; return;
List<SSeries> series = _GetSeries(); List<SSeries> series = _GetSeries();
@@ -883,41 +431,44 @@ namespace VocaluxeLib.Songs
Medley.StartBeat = voice.Lines[series[longest].Start].FirstNoteBeat; Medley.StartBeat = voice.Lines[series[longest].Start].FirstNoteBeat;
Medley.EndBeat = voice.Lines[series[longest].End].LastNoteBeat; Medley.EndBeat = voice.Lines[series[longest].End].LastNoteBeat;
bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) + CBase.Settings.GetMedleyMinDuration() > bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) < CBase.Settings.GetMedleyMinDuration();
CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM);
// set end if duration > MedleyMinDuration // set end if duration < MedleyMinDuration
if (!foundEnd) 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() > if (CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) <
CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM)) CBase.Settings.GetMedleyMinDuration())
{ {
foundEnd = true; foundEnd = true;
Medley.EndBeat = voice.Lines[i].LastNoteBeat; Medley.EndBeat = voice.Lines[i].LastNoteBeat;
break;
} }
} }
} }
if (foundEnd) if (foundEnd)
{ {
Medley.Source = EMedleySource.Calculated; Medley.Source = EDataSource.Calculated;
Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime(); Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime(); Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
} }
} }
if (Math.Abs(PreviewStart) < 0.001) if (Preview.Source == EDataSource.None)
{ {
if (Medley.Source == EMedleySource.Calculated) if (Medley.Source != EDataSource.None)
PreviewStart = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM); Preview.StartTime = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM);
} }
} }
private void _FindShortEnd() private void _FindShortEnd()
{ {
if (ShortEnd.Source != EDataSource.None)
return;
List<SSeries> series = _GetSeries(); List<SSeries> series = _GetSeries();
if (series == null) if (series == null)
return; 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))) 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; return;
} }
ShortEnd = voice.Lines[series[i].End].LastNote.EndBeat; ShortEnd.EndBeat = voice.Lines[series[i].End].LastNote.EndBeat;
return; return;
} }
} }
@@ -947,12 +498,13 @@ namespace VocaluxeLib.Songs
{ {
if (line.FirstNoteBeat < stop && line.LastNoteBeat > stop) if (line.FirstNoteBeat < stop && line.LastNoteBeat > stop)
{ {
ShortEnd = line.LastNoteBeat; ShortEnd.EndBeat = line.LastNoteBeat;
return; return;
} }
} }
ShortEnd = stop; ShortEnd.EndBeat = stop;
ShortEnd.Source = EDataSource.Calculated;
} }
} }
} }
+16 -12
View File
@@ -22,7 +22,7 @@ namespace VocaluxeLib.Songs
{ {
public class CSongLine : CLineBase<CSongNote> public class CSongLine : CLineBase<CSongNote>
{ {
private int _StartBeat = int.MinValue; private int _StartBeat = int.MaxValue;
private int _EndBeat = int.MinValue; private int _EndBeat = int.MinValue;
#region Constructors #region Constructors
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
public int StartBeat public int StartBeat
{ {
get { return _StartBeat; } get { return Math.Min(_StartBeat, FirstNoteBeat); }
set set
{ {
if (value <= FirstNoteBeat) if (value <= FirstNoteBeat)
@@ -56,7 +56,7 @@ namespace VocaluxeLib.Songs
public int EndBeat public int EndBeat
{ {
get { return _EndBeat; } get { return Math.Min(_EndBeat, LastNoteBeat); }
set set
{ {
if (value >= LastNoteBeat) if (value >= LastNoteBeat)
@@ -77,12 +77,19 @@ namespace VocaluxeLib.Songs
_Notes.Add(note); _Notes.Add(note);
else else
{ {
//Insert AFTER this note
int insPos = FindPreviousNote(note.StartBeat); int insPos = FindPreviousNote(note.StartBeat);
//Check for overlapping notes //Check for overlapping notes
if (insPos >= 0 && _Notes[insPos].EndBeat > note.StartBeat) if (insPos >= 0) //Check note before
return false; {
if (insPos < _Notes.Count - 1 && _Notes[insPos + 1].StartBeat > note.EndBeat) if (_Notes[insPos].EndBeat >= note.StartBeat)
return false; return false;
}
if (insPos < _Notes.Count - 1) //Check note after
{
if (_Notes[insPos + 1].StartBeat <= note.EndBeat)
return false;
}
_Notes.Insert(insPos + 1, note); _Notes.Insert(insPos + 1, note);
} }
return true; return true;
@@ -90,11 +97,8 @@ namespace VocaluxeLib.Songs
public void SetMedley(int startBeat, int endBeat) public void SetMedley(int startBeat, int endBeat)
{ {
foreach (CSongNote note in _Notes) foreach (CSongNote note in _Notes.Where(note => note.StartBeat < startBeat || note.EndBeat > endBeat))
{ note.Type = ENoteType.Freestyle;
if (note.StartBeat < startBeat || note.EndBeat > endBeat)
note.NoteType = ENoteType.Freestyle;
}
VisibleInTimeLine = FirstNoteBeat >= startBeat && LastNoteBeat <= endBeat; VisibleInTimeLine = FirstNoteBeat >= startBeat && LastNoteBeat <= endBeat;
} }
+740
View File
@@ -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 &lt; 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 &lt; 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);
}
}
}
}
+4 -4
View File
@@ -25,20 +25,20 @@ namespace VocaluxeLib.Songs
#region Contructors #region Contructors
public CSongNote(CSongNote note) : base(note) public CSongNote(CSongNote note) : base(note)
{ {
NoteType = note.NoteType; Type = note.Type;
Text = note.Text; Text = note.Text;
} }
public CSongNote(int startBeat, int duration, int tone, string text, ENoteType noteType) public CSongNote(int startBeat, int duration, int tone, string text, ENoteType noteType)
: base(startBeat, duration, tone) : base(startBeat, duration, tone)
{ {
NoteType = noteType; Type = noteType;
Text = text; Text = text;
} }
#endregion Constructors #endregion Constructors
#region Properties #region Properties
public ENoteType NoteType { get; set; } public ENoteType Type { get; set; }
public string Text { get; set; } public string Text { get; set; }
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
{ {
get get
{ {
switch (NoteType) switch (Type)
{ {
case ENoteType.Normal: case ENoteType.Normal:
return 1; return 1;
+171
View File
@@ -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;
}
}
}
}
+1 -1
View File
@@ -48,7 +48,7 @@ namespace VocaluxeLib.Songs
} }
#region Properties #region Properties
public double Points; public new double Points;
// for drawing player notes // for drawing player notes
public bool Hit public bool Hit
{ {
+85 -14
View File
@@ -15,6 +15,7 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>. // along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -67,7 +68,11 @@ namespace VocaluxeLib.Songs
} }
#region Methods #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) public int FindPreviousLine(int beat)
{ {
//If no line -> No previous line //If no line -> No previous line
@@ -92,15 +97,49 @@ namespace VocaluxeLib.Songs
return start; return start;
} }
public void AddLine(CSongLine line) public bool AddLine(CSongLine line, bool updateTimings = true)
{ {
if (_Lines.Count == 0) if (_Lines.Count == 0)
_Lines.Add(line); _Lines.Add(line);
else else
{ {
int insPos = FindPreviousLine(line.StartBeat); 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); _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) public bool DeleteLine(int index)
@@ -119,15 +158,26 @@ namespace VocaluxeLib.Songs
_Lines.Clear(); _Lines.Clear();
} }
public bool AddNote(CSongNote note, bool updateTimings = false) public bool AddNote(CSongNote note, bool updateTimings = true)
{ {
int lineIndex = FindPreviousLine(note.StartBeat); 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) if (lineIndex < 0)
{ {
//Note is before ALL lines //Note is before ALL lines
var line = new CSongLine {StartBeat = note.StartBeat}; if (_Lines.Count > 0)
line.AddNote(note); {
_Lines.Insert(0, line); //Add to first line
if (!_Lines[0].AddNote(note))
return false;
}
else
{
var line = new CSongLine();
line.AddNote(note);
_Lines.Add(line);
}
} }
else else
{ {
@@ -139,24 +189,27 @@ namespace VocaluxeLib.Songs
return true; 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) if (_Lines.Count > lineIndex && _Lines[lineIndex].StartBeat <= note.StartBeat)
{ {
_Lines[lineIndex].AddNote(note); if (!_Lines[lineIndex].AddNote(note))
return false;
if (updateTimings) if (updateTimings)
UpdateTimings(); UpdateTimings();
return true; return true;
} }
return false; return false;
} }*/
public void UpdateTimings() public void UpdateTimings()
{ {
CSongNote lastNote; CSongNote lastNote;
if (_Lines.Count > 0) if (_Lines.Count == 0)
_Lines[0].StartBeat = -10000; return;
_Lines[0].StartBeat = -10000;
for (int i = 1; i < _Lines.Count; i++) for (int i = 1; i < _Lines.Count; i++)
{ {
@@ -191,11 +244,24 @@ namespace VocaluxeLib.Songs
_Lines[i].StartBeat = s; _Lines[i].StartBeat = s;
_Lines[i - 1].EndBeat = min; _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; _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
if (lastNote != null)
_Lines[_Lines.Count - 1].EndBeat = lastNote.EndBeat;
} }
public void SetMedley(int startBeat, int endBeat) public void SetMedley(int startBeat, int endBeat)
@@ -204,5 +270,10 @@ namespace VocaluxeLib.Songs
line.SetMedley(startBeat, endBeat); line.SetMedley(startBeat, endBeat);
} }
#endregion Methods #endregion Methods
public int RemoveEmptyLines()
{
return _Lines.RemoveAll(line => line.NoteCount == 0);
}
} }
} }
+3
View File
@@ -130,6 +130,7 @@
<Reference Include="System.XML" /> <Reference Include="System.XML" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="GlobalSuppressions.cs" /> <Compile Include="GlobalSuppressions.cs" />
<Compile Include="IBasic.cs" /> <Compile Include="IBasic.cs" />
<Compile Include="Menu\CBackground.cs" /> <Compile Include="Menu\CBackground.cs" />
@@ -174,9 +175,11 @@
<Compile Include="Menu\SongMenu\CSongMenuList.cs" /> <Compile Include="Menu\SongMenu\CSongMenuList.cs" />
<Compile Include="Menu\SongMenu\CSongMenuTileBoard.cs" /> <Compile Include="Menu\SongMenu\CSongMenuTileBoard.cs" />
<Compile Include="Menu\SongMenu\ISongMenu.cs" /> <Compile Include="Menu\SongMenu\ISongMenu.cs" />
<Compile Include="Songs\CSongWriter.cs" />
<Compile Include="Songs\CSungLine.cs" /> <Compile Include="Songs\CSungLine.cs" />
<Compile Include="Songs\CSungNote.cs" /> <Compile Include="Songs\CSungNote.cs" />
<Compile Include="Songs\CVoice.cs" /> <Compile Include="Songs\CVoice.cs" />
<Compile Include="Songs\CSongLoader.cs" />
<Compile Include="Structs.cs" /> <Compile Include="Structs.cs" />
<Compile Include="PartyModes\CPartyMode.cs" /> <Compile Include="PartyModes\CPartyMode.cs" />
<Compile Include="PartyModes\CPartyModeNone.cs" /> <Compile Include="PartyModes\CPartyModeNone.cs" />