Merge branch 'develop' into Better_Rounds_Handling
Conflicts: Vocaluxe/Base/CGame.cs Vocaluxe/Screens/CScreenNames.cs
This commit is contained in:
commit
f8b80a5911
53 files changed
+2014
-1281
No files matched your search
@@ -69,13 +69,12 @@ int GstreamerAudioStream::Load(const wchar_t* Media)
|
||||
return -1;
|
||||
}
|
||||
Running = true;
|
||||
gst_element_set_state(Element, GST_STATE_NULL);
|
||||
g_object_set(Element, "uri", Media, NULL);
|
||||
g_object_set(Element, "audio-sink", SinkBin, NULL);
|
||||
g_object_set(Element, "flags", GST_PLAY_FLAG_AUDIO, NULL);
|
||||
|
||||
gst_element_set_state(Element, GST_STATE_PAUSED);
|
||||
//gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||
RefreshDuration();
|
||||
|
||||
return ID;
|
||||
}
|
||||
@@ -84,8 +83,15 @@ int GstreamerAudioStream::Load(const wchar_t* Media)
|
||||
int GstreamerAudioStream::Load(const wchar_t* Media, bool Prescan)
|
||||
{
|
||||
Load(Media);
|
||||
if(Prescan)
|
||||
if(Prescan){
|
||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||
//Workaround: Waiting for the stream to be loaded (Length>0)
|
||||
for(int i=0;i<40;i++){
|
||||
if(GetLength()>0.f)
|
||||
break;
|
||||
Sleep(5);
|
||||
}
|
||||
}
|
||||
return ID;
|
||||
}
|
||||
|
||||
@@ -127,10 +133,7 @@ void GstreamerAudioStream::Play(void)
|
||||
{
|
||||
PauseStreamAfterFade = false;
|
||||
Running = true;
|
||||
GstStateChangeReturn ret;
|
||||
if(Element)
|
||||
ret = gst_element_set_state(Element, GST_STATE_PLAYING);
|
||||
if(ret == GST_STATE_CHANGE_ASYNC)
|
||||
if(gst_element_set_state(Element, GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC)
|
||||
gst_bus_timed_pop_filtered(Bus, -1, GST_MESSAGE_ASYNC_DONE);
|
||||
SetStreamVolume(Volume * 100.0);
|
||||
}
|
||||
@@ -180,7 +183,7 @@ void GstreamerAudioStream::SetStreamVolumeMax(float MaxVolume)
|
||||
|
||||
float GstreamerAudioStream::GetLength()
|
||||
{
|
||||
if(Duration <= 0)
|
||||
if(Duration <= 0.f)
|
||||
RefreshDuration();
|
||||
return Duration;
|
||||
}
|
||||
@@ -191,7 +194,7 @@ void GstreamerAudioStream::RefreshDuration()
|
||||
{
|
||||
gint64 time = -1000;
|
||||
if(gst_element_query_duration(Element, GST_FORMAT_TIME, &time))
|
||||
Duration = (gfloat)((gdouble)(time/GST_SECOND));
|
||||
Duration = (gfloat)((gdouble)time/GST_SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -675,7 +675,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
|
||||
case ESongSource.TR_CATEGORY:
|
||||
CBase.Songs.SetCategory(_GameData.CategoryID);
|
||||
for (int i = 0; i < CBase.Songs.NumSongsInCategory(_GameData.CategoryID); i++)
|
||||
for (int i = 0; i < CBase.Songs.GetNumSongsVisible(); i++)
|
||||
{
|
||||
// ReSharper disable LoopCanBeConvertedToQuery
|
||||
foreach (EGameMode mode in CBase.Songs.GetVisibleSong(i).AvailableGameModes)
|
||||
|
||||
@@ -20,6 +20,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
{
|
||||
@@ -59,7 +60,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
_ThemeButtons = new string[] {_ButtonNext, _ButtonBack};
|
||||
|
||||
_Data = new SDataFromScreen();
|
||||
SFromScreenConfig config = new SFromScreenConfig
|
||||
var config = new SFromScreenConfig
|
||||
{
|
||||
PlaylistID = 0,
|
||||
NumFields = 9,
|
||||
@@ -76,7 +77,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
{
|
||||
try
|
||||
{
|
||||
SDataToScreenConfig config = (SDataToScreenConfig)receivedData;
|
||||
var config = (SDataToScreenConfig)receivedData;
|
||||
_Data.ScreenConfig.NumFields = config.NumFields;
|
||||
_Data.ScreenConfig.NumPlayerTeam1 = config.NumPlayerTeam1;
|
||||
_Data.ScreenConfig.NumPlayerTeam2 = config.NumPlayerTeam2;
|
||||
@@ -207,13 +208,13 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
_SelectSlides[_SelectSlidePlaylist].Selection = _Data.ScreenConfig.PlaylistID;
|
||||
_SelectSlides[_SelectSlidePlaylist].Visible = _Data.ScreenConfig.SongSource == ESongSource.TR_PLAYLIST;
|
||||
|
||||
string[] categories = new string[CBase.Songs.GetNumCategories()];
|
||||
var categories = new string[CBase.Songs.GetNumCategories()];
|
||||
for (int i = 0; i < CBase.Songs.GetNumCategories(); i++)
|
||||
categories[i] = CBase.Songs.GetCategory(i).Name;
|
||||
_SelectSlides[_SelectSlideCategory].Clear();
|
||||
for (int i = 0; i < categories.Length; i++)
|
||||
{
|
||||
string value = categories[i] + " (" + CBase.Songs.NumSongsInCategory(i) + " " + CBase.Language.Translate("TR_SONGS", _PartyModeID) + ")";
|
||||
string value = categories[i] + " (" + CBase.Songs.GetNumSongsNotSungInCategory(i) + " " + CBase.Language.Translate("TR_SONGS", _PartyModeID) + ")";
|
||||
_SelectSlides[_SelectSlideCategory].AddValue(value);
|
||||
}
|
||||
_SelectSlides[_SelectSlideCategory].Selection = _Data.ScreenConfig.CategoryID;
|
||||
@@ -240,7 +241,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
_Data.ScreenConfig.CategoryID = _SelectSlides[_SelectSlideCategory].Selection;
|
||||
_Data.ScreenConfig.GameMode = (EPartyGameMode)_SelectSlides[_SelectSlideGameMode].Selection;
|
||||
|
||||
EGameMode gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
|
||||
switch (_Data.ScreenConfig.GameMode)
|
||||
{
|
||||
@@ -280,25 +281,22 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
}
|
||||
if (_Data.ScreenConfig.SongSource == ESongSource.TR_CATEGORY)
|
||||
{
|
||||
if (CBase.Songs.GetNumCategories() > 0)
|
||||
{
|
||||
if (CBase.Songs.NumSongsInCategory(_Data.ScreenConfig.CategoryID) > 0)
|
||||
{
|
||||
CBase.Songs.SetCategory(_Data.ScreenConfig.CategoryID);
|
||||
_ConfigOk = false;
|
||||
for (int i = 0; i < CBase.Songs.NumSongsInCategory(_Data.ScreenConfig.CategoryID); i++)
|
||||
{
|
||||
_ConfigOk = CBase.Songs.GetVisibleSong(i).AvailableGameModes.Any(mode => mode == gm);
|
||||
if (_ConfigOk)
|
||||
break;
|
||||
}
|
||||
CBase.Songs.SetCategory(-1);
|
||||
}
|
||||
else
|
||||
_ConfigOk = false;
|
||||
}
|
||||
else
|
||||
if (CBase.Songs.GetNumCategories() == 0)
|
||||
_ConfigOk = false;
|
||||
else if (CBase.Songs.GetNumSongsNotSungInCategory(_Data.ScreenConfig.CategoryID) <= 0)
|
||||
_ConfigOk = false;
|
||||
else
|
||||
{
|
||||
CBase.Songs.SetCategory(_Data.ScreenConfig.CategoryID);
|
||||
_ConfigOk = false;
|
||||
foreach (CSong song in CBase.Songs.GetVisibleSongs())
|
||||
{
|
||||
_ConfigOk = song.AvailableGameModes.Any(mode => mode == gm);
|
||||
if (_ConfigOk)
|
||||
break;
|
||||
}
|
||||
CBase.Songs.SetCategory(-1);
|
||||
}
|
||||
}
|
||||
if (_Data.ScreenConfig.SongSource == ESongSource.TR_ALLSONGS)
|
||||
{
|
||||
|
||||
@@ -504,7 +504,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
CBase.BackgroundMusic.SetStatus(true);
|
||||
|
||||
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.PreviewStart);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.Preview.StartTime);
|
||||
CBase.Sound.SetStreamVolume(_PreviewStream, 0f);
|
||||
CBase.Sound.Play(_PreviewStream);
|
||||
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
|
||||
@@ -528,7 +528,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
|
||||
CBase.BackgroundMusic.SetStatus(true);
|
||||
|
||||
_PreviewStream = CBase.Sound.Load(song.GetMP3(), false);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.PreviewStart);
|
||||
CBase.Sound.SetPosition(_PreviewStream, song.Preview.StartTime);
|
||||
CBase.Sound.SetStreamVolume(_PreviewStream, 0f);
|
||||
CBase.Sound.Play(_PreviewStream);
|
||||
CBase.Sound.Fade(_PreviewStream, CBase.Config.GetBackgroundMusicVolume(), 1f);
|
||||
|
||||
+1
-4
@@ -1,6 +1,6 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Express 2012 for Windows Desktop
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{6F3E1874-F28A-40E9-AFBD-31934D593678} = {6F3E1874-F28A-40E9-AFBD-31934D593678}
|
||||
@@ -154,7 +154,4 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -90,11 +90,6 @@ namespace Vocaluxe.Base
|
||||
get { return _CurrentPlaylistElement.SongID; }
|
||||
}
|
||||
|
||||
public static bool Duet
|
||||
{
|
||||
get { return _CurrentPlaylistElement.Duet; }
|
||||
}
|
||||
|
||||
public static bool SongHasVideo
|
||||
{
|
||||
get { return File.Exists(_CurrentPlaylistElement.VideoFilePath); }
|
||||
@@ -581,17 +576,6 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
}
|
||||
|
||||
public bool Duet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Song != null)
|
||||
return _Song.IsDuet;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public CPlaylistElement(CSong song)
|
||||
{
|
||||
MusicFilePath = string.Empty;
|
||||
|
||||
@@ -33,10 +33,19 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
static class CConfig
|
||||
{
|
||||
private static readonly XmlWriterSettings _Settings = new XmlWriterSettings();
|
||||
/// <summary>
|
||||
/// Uniform settings for writing XML files. ALWAYS use this!
|
||||
/// </summary>
|
||||
public static readonly XmlWriterSettings XMLSettings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
Encoding = Encoding.UTF8,
|
||||
ConformanceLevel = ConformanceLevel.Document
|
||||
};
|
||||
|
||||
// Debug
|
||||
public static EDebugLevel DebugLevel = EDebugLevel.TR_CONFIG_OFF;
|
||||
public static EOffOn SaveModifiedSongs = EOffOn.TR_CONFIG_OFF;
|
||||
|
||||
// Graphics
|
||||
#if WIN
|
||||
@@ -140,10 +149,6 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_Settings.Indent = true;
|
||||
_Settings.Encoding = Encoding.UTF8;
|
||||
_Settings.ConformanceLevel = ConformanceLevel.Document;
|
||||
|
||||
SongFolder.Add(Path.Combine(Directory.GetCurrentDirectory(), CSettings.FolderSongs));
|
||||
|
||||
#if INSTALLER
|
||||
@@ -169,6 +174,7 @@ namespace Vocaluxe.Base
|
||||
return;
|
||||
|
||||
xmlReader.TryGetEnumValue("//root/Debug/DebugLevel", ref DebugLevel);
|
||||
xmlReader.TryGetEnumValue("//root/Debug/SaveModifiedSongs", ref SaveModifiedSongs);
|
||||
|
||||
#region Graphics
|
||||
xmlReader.TryGetEnumValue("//root/Graphics/Renderer", ref Renderer);
|
||||
@@ -302,7 +308,7 @@ namespace Vocaluxe.Base
|
||||
XmlWriter writer = null;
|
||||
try
|
||||
{
|
||||
writer = XmlWriter.Create(Path.Combine(CSettings.DataPath, CSettings.FileConfig), _Settings);
|
||||
writer = XmlWriter.Create(Path.Combine(CSettings.DataPath, CSettings.FileConfig), XMLSettings);
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("root");
|
||||
|
||||
@@ -328,6 +334,9 @@ namespace Vocaluxe.Base
|
||||
writer.WriteComment("DebugLevel: " + CHelper.ListStrings(Enum.GetNames(typeof(EDebugLevel))));
|
||||
writer.WriteElementString("DebugLevel", Enum.GetName(typeof(EDebugLevel), DebugLevel));
|
||||
|
||||
writer.WriteComment("SaveModifiedSongs: " + CHelper.ListStrings(Enum.GetNames(typeof(EOffOn))));
|
||||
writer.WriteElementString("SaveModifiedSongs", Enum.GetName(typeof(EOffOn), SaveModifiedSongs));
|
||||
|
||||
writer.WriteEndElement();
|
||||
#endregion Debug
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ namespace Vocaluxe.Base
|
||||
for (int beat = _LastEvalBeat + 1; beat <= RecordedBeat; beat++)
|
||||
{
|
||||
if ((_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_MEDLEY && song.Medley.EndBeat == beat) ||
|
||||
(_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_SHORTSONG && song.ShortEnd == beat))
|
||||
(_SongQueue.GetCurrentGameMode() == EGameMode.TR_GAMEMODE_SHORTSONG && song.ShortEnd.EndBeat == beat))
|
||||
Players[p].SongFinished = true;
|
||||
|
||||
CSongLine[] lines = song.Notes.GetVoice(Players[p].VoiceNr).Lines;
|
||||
@@ -288,7 +288,7 @@ namespace Vocaluxe.Base
|
||||
//CSound.RecordSetTone(p, Tone);
|
||||
double points = (CSettings.MaxScore - CSettings.LinebonusScore) * (double)notes[note].PointsForBeat /
|
||||
song.Notes.GetVoice(Players[p].VoiceNr).Points;
|
||||
if (notes[note].NoteType == ENoteType.Golden)
|
||||
if (notes[note].Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes += points;
|
||||
|
||||
Players[p].Points += points;
|
||||
@@ -382,7 +382,7 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
if (note.StartBeat < nextStart)
|
||||
{
|
||||
if (note.Hit && note.HitNote.NoteType == ENoteType.Golden)
|
||||
if (note.Hit && note.HitNote.Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes += note.Points;
|
||||
Players[p].Points += note.Points;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ namespace Vocaluxe.Base
|
||||
}
|
||||
while (line.NoteCount > n && n >= 0)
|
||||
{
|
||||
if (line.Notes[n].Hit && line.Notes[n].HitNote.NoteType == ENoteType.Golden)
|
||||
if (line.Notes[n].Hit && line.Notes[n].HitNote.Type == ENoteType.Golden)
|
||||
Players[p].PointsGoldenNotes -= line.Notes[n].Points;
|
||||
Players[p].Points -= line.Notes[n].Points;
|
||||
line.DeleteNote(n);
|
||||
|
||||
@@ -117,8 +117,7 @@ namespace Vocaluxe.Base
|
||||
MessageBox.Show(errorText, CSettings.ProgramName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
if (e != null)
|
||||
errorText += ": " + e;
|
||||
_ErrorLog.Add(_NumErrors + ") " + errorText + "\r\n");
|
||||
_ErrorLog.Add(String.Empty);
|
||||
_ErrorLog.Add(_NumErrors + ") " + errorText);
|
||||
if (exit)
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
|
||||
+25
-7
@@ -19,6 +19,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Xml;
|
||||
using Vocaluxe.Base.Fonts;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Game;
|
||||
@@ -60,6 +61,11 @@ namespace Vocaluxe.Base
|
||||
|
||||
class CBconfig : IConfig
|
||||
{
|
||||
public EOffOn GetSaveModifiedSongs()
|
||||
{
|
||||
return CConfig.SaveModifiedSongs;
|
||||
}
|
||||
|
||||
public void SetBackgroundMusicVolume(int newVolume)
|
||||
{
|
||||
CConfig.BackgroundMusicVolume = newVolume;
|
||||
@@ -110,7 +116,7 @@ namespace Vocaluxe.Base
|
||||
return CConfig.CoverSize;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetSongFolder()
|
||||
public IEnumerable<string> GetSongFolders()
|
||||
{
|
||||
return CConfig.SongFolder;
|
||||
}
|
||||
@@ -139,6 +145,11 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
return CConfig.GetMaxNumMics();
|
||||
}
|
||||
|
||||
public XmlWriterSettings GetXMLSettings()
|
||||
{
|
||||
return CConfig.XMLSettings;
|
||||
}
|
||||
}
|
||||
|
||||
class CBsettings : ISettings
|
||||
@@ -527,6 +538,11 @@ namespace Vocaluxe.Base
|
||||
return CGame.GetTimeFromBeats(beat, bpm);
|
||||
}
|
||||
|
||||
public float GetBeatFromTime(float time, float bpm, float gap)
|
||||
{
|
||||
return CGame.GetBeatFromTime(time, bpm, gap);
|
||||
}
|
||||
|
||||
public void AddSong(int songID, EGameMode gameMode)
|
||||
{
|
||||
CGame.AddSong(songID, gameMode);
|
||||
@@ -596,9 +612,14 @@ namespace Vocaluxe.Base
|
||||
return CSongs.NumCategories;
|
||||
}
|
||||
|
||||
public int NumSongsInCategory(int categoryIndex)
|
||||
public int GetNumSongsInCategory(int categoryIndex)
|
||||
{
|
||||
return CSongs.NumSongsInCategory(categoryIndex);
|
||||
return CSongs.GetNumSongsInCategory(categoryIndex);
|
||||
}
|
||||
|
||||
public int GetNumSongsNotSungInCategory(int categoryIndex)
|
||||
{
|
||||
return CSongs.GetNumSongsNotSungInCategory(categoryIndex);
|
||||
}
|
||||
|
||||
public bool IsInCategory()
|
||||
@@ -653,10 +674,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public CCategory GetCategory(int index)
|
||||
{
|
||||
if (index >= CSongs.NumCategories)
|
||||
return null;
|
||||
|
||||
return new CCategory(CSongs.Categories[index]);
|
||||
return CSongs.GetCategoryByIndex(index);
|
||||
}
|
||||
|
||||
public void AddPartySongSung(int songID)
|
||||
|
||||
@@ -157,10 +157,10 @@ namespace Vocaluxe.Base
|
||||
switch (_SongSorting)
|
||||
{
|
||||
case ESongSorting.TR_CONFIG_EDITION:
|
||||
fieldName = "Edition";
|
||||
fieldName = "Editions";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_GENRE:
|
||||
fieldName = "Genre";
|
||||
fieldName = "Genres";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_FOLDER:
|
||||
fieldName = "FolderName";
|
||||
@@ -177,7 +177,7 @@ namespace Vocaluxe.Base
|
||||
fieldName = "Year";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_LANGUAGE:
|
||||
fieldName = "Language";
|
||||
fieldName = "Languages";
|
||||
break;
|
||||
case ESongSorting.TR_CONFIG_DATEADDED:
|
||||
fieldName = "DateAdded";
|
||||
|
||||
+34
-7
@@ -64,7 +64,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
public static int NumSongsVisible
|
||||
{
|
||||
get { return _CatIndex < 0 ? 0 : Categories[_CatIndex].Songs.Count(sp => !sp.IsSung); }
|
||||
get { return VisibleSongs.Count; }
|
||||
}
|
||||
|
||||
public static int NumCategories
|
||||
@@ -102,9 +102,19 @@ namespace Vocaluxe.Base
|
||||
/// </summary>
|
||||
/// <param name="catIndex">Category index</param>
|
||||
/// <returns></returns>
|
||||
public static int NumSongsInCategory(int catIndex)
|
||||
public static int GetNumSongsInCategory(int catIndex)
|
||||
{
|
||||
return _IsCatIndexValid(catIndex) ? Categories[catIndex].Songs.Count(sp => !sp.IsSung) : 0;
|
||||
return _IsCatIndexValid(catIndex) ? Categories[catIndex].Songs.Count : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of song that are not sung in the category specified with CatIndex
|
||||
/// </summary>
|
||||
/// <param name="catIndex">Category index</param>
|
||||
/// <returns>Number of visible songs in that category</returns>
|
||||
public static int GetNumSongsNotSungInCategory(int catIndex)
|
||||
{
|
||||
return _IsCatIndexValid(catIndex) ? Categories[catIndex].GetNumSongsNotSung() : 0;
|
||||
}
|
||||
|
||||
public static void NextCategory()
|
||||
@@ -157,9 +167,8 @@ namespace Vocaluxe.Base
|
||||
foreach (CSongPointer song in category.Songs.Where(song => song.SongID == songID))
|
||||
{
|
||||
song.IsSung = true;
|
||||
int catIndex = _GetCategoryNumber(category);
|
||||
if (NumSongsInCategory(catIndex) == 0)
|
||||
ResetPartySongSung(catIndex);
|
||||
if (category.GetNumSongsNotSung() == 0)
|
||||
ResetPartySongSung(_GetCategoryNumber(category));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -269,6 +278,24 @@ namespace Vocaluxe.Base
|
||||
get { return Categorizer.Categories.AsReadOnly(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets category with given index or null for invalid index
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns>category with given index or null for invalid index</returns>
|
||||
public static CCategory GetCategoryByIndex(int index)
|
||||
{
|
||||
if (!_IsCatIndexValid(index))
|
||||
return null;
|
||||
|
||||
return Categorizer.Categories[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets visible song with given index or null for invalid index or song not visible
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns>visible song with given index or null for invalid index or song not visible</returns>
|
||||
public static CSong GetVisibleSongByIndex(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
@@ -312,7 +339,7 @@ namespace Vocaluxe.Base
|
||||
if (song == null)
|
||||
continue;
|
||||
song.ID = _Songs.Count;
|
||||
if (song.ReadNotes())
|
||||
if (song.LoadNotes())
|
||||
_Songs.Add(song);
|
||||
}
|
||||
CLog.StopBenchmark(2, "Read TXTs");
|
||||
|
||||
@@ -105,7 +105,6 @@ namespace Vocaluxe.Base
|
||||
private const int _SkinSystemVersion = 3;
|
||||
|
||||
#region Vars
|
||||
private static readonly XmlWriterSettings _Settings = new XmlWriterSettings();
|
||||
private static readonly List<STheme> _Themes = new List<STheme>();
|
||||
public static string[] ThemeNames
|
||||
{
|
||||
@@ -146,10 +145,6 @@ namespace Vocaluxe.Base
|
||||
#region Theme and Skin loading and writing
|
||||
public static void InitTheme()
|
||||
{
|
||||
_Settings.Indent = true;
|
||||
_Settings.Encoding = Encoding.UTF8;
|
||||
_Settings.ConformanceLevel = ConformanceLevel.Document;
|
||||
|
||||
_ListThemes();
|
||||
ListSkins();
|
||||
|
||||
@@ -289,7 +284,7 @@ namespace Vocaluxe.Base
|
||||
private static void _SaveTheme(int themeIndex)
|
||||
{
|
||||
#region ThemeMainFile
|
||||
using (XmlWriter writer = XmlWriter.Create(Path.Combine(_Themes[themeIndex].Path, _Themes[themeIndex].FileName), _Settings))
|
||||
using (XmlWriter writer = XmlWriter.Create(Path.Combine(_Themes[themeIndex].Path, _Themes[themeIndex].FileName), CConfig.XMLSettings))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("root");
|
||||
@@ -331,7 +326,7 @@ namespace Vocaluxe.Base
|
||||
{
|
||||
for (int skinIndex = 0; skinIndex < _Skins.Count; skinIndex++)
|
||||
{
|
||||
using (XmlWriter writer = XmlWriter.Create(Path.Combine(_Skins[skinIndex].Path, _Skins[skinIndex].FileName), _Settings))
|
||||
using (XmlWriter writer = XmlWriter.Create(Path.Combine(_Skins[skinIndex].Path, _Skins[skinIndex].FileName), CConfig.XMLSettings))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("root");
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using Vocaluxe.Base;
|
||||
|
||||
namespace Vocaluxe
|
||||
{
|
||||
/// <summary>
|
||||
/// Some helper functions for the programm
|
||||
/// </summary>
|
||||
static class CProgrammHelper
|
||||
{
|
||||
private static bool _CheckUninstallKey(string name, string key)
|
||||
{
|
||||
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(key))
|
||||
{
|
||||
if (rk == null)
|
||||
throw new SecurityException();
|
||||
foreach (string skName in rk.GetSubKeyNames())
|
||||
{
|
||||
using (RegistryKey sk = rk.OpenSubKey(skName))
|
||||
{
|
||||
if (sk == null || sk.GetValue("DisplayName") == null)
|
||||
continue;
|
||||
string displayName = sk.GetValue("DisplayName").ToString().ToLower();
|
||||
if (displayName.Equals(name) || displayName.StartsWith(name) || name.StartsWith(displayName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given program is installed by checking the Uninstall registry key.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the programm. Got to equal the displayname in the key or one needs to be the start of the other one. NOT case sensitive.</param>
|
||||
/// <returns></returns>
|
||||
private static bool _IsProgramInstalled(string name)
|
||||
{
|
||||
const string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||
const string uninstallKeyx64 = @"SOFTWARE\WoW6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||
name = name.ToLower();
|
||||
return _CheckUninstallKey(name, uninstallKey) || _CheckUninstallKey(name, uninstallKeyx64);
|
||||
}
|
||||
|
||||
private static bool _SystemDllExists(string dllName)
|
||||
{
|
||||
const string sysDir = "%windir%\\system32\\";
|
||||
return File.Exists(Environment.ExpandEnvironmentVariables(sysDir + dllName + ".dll"));
|
||||
}
|
||||
|
||||
private static bool _IsVC2012Installed()
|
||||
{
|
||||
return _SystemDllExists("msvcr110") && _SystemDllExists("msvcp110");
|
||||
}
|
||||
|
||||
private static bool _IsVC2008Installed()
|
||||
{
|
||||
return _IsProgramInstalled("Microsoft Visual C++ 2008 Redistributable");
|
||||
}
|
||||
|
||||
private static bool _IsVC2010Installed()
|
||||
{
|
||||
//Note: Maybe check for x64 or x86
|
||||
return _IsProgramInstalled("Microsoft Visual C++ 2010");
|
||||
}
|
||||
|
||||
public static bool CheckRequirements()
|
||||
{
|
||||
if (!_IsVC2012Installed())
|
||||
{
|
||||
CLog.LogError(
|
||||
"VC++ 2012 Redistributables are missing. Please install them first.\r\nDownload: http://www.microsoft.com/de-de/download/details.aspx?id=30679",
|
||||
true, true);
|
||||
return false;
|
||||
}
|
||||
bool vc2008Installed = _IsVC2008Installed();
|
||||
if (!vc2008Installed)
|
||||
{
|
||||
CLog.LogError(
|
||||
"VC++ 2008 Redistributables are missing. Portaudio might not be working.\r\nDownload: http://www.microsoft.com/de-de/download/details.aspx?id=29");
|
||||
}
|
||||
if (!vc2008Installed && !_IsVC2010Installed())
|
||||
{
|
||||
CLog.LogError(
|
||||
"VC++ 2010 and 2008 Redistributables are missing. Please install them first. VC++ 2008 is preferred as Portaudio doesn't work with VC++ 2010.\r\nDownload(2008): http://www.microsoft.com/de-de/download/details.aspx?id=29 \r\nDownload(2010): http://www.microsoft.com/de-de/download/details.aspx?id=5555",
|
||||
true, true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
return song;
|
||||
return (song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_NORMAL)) ? song : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
return (song.IsDuet) ? song : null;
|
||||
return (song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET)) ? song : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,11 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
var newSong = new CSong(song) {Finish = CGame.GetTimeFromBeats(song.ShortEnd, song.BPM) + CSettings.DefaultMedleyFadeOutTime + song.Gap};
|
||||
if (!song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_SHORTSONG))
|
||||
return null;
|
||||
var newSong = new CSong(song) {Finish = CGame.GetTimeFromBeats(song.ShortEnd.EndBeat, song.BPM) + CSettings.DefaultMedleyFadeOutTime + song.Gap};
|
||||
// set lines to short mode
|
||||
newSong.Notes.SetMedley(song.Notes.GetVoice(0).Lines[0].FirstNoteBeat, song.ShortEnd);
|
||||
newSong.Notes.SetMedley(0, song.ShortEnd.EndBeat);
|
||||
|
||||
return newSong;
|
||||
}
|
||||
@@ -80,6 +82,8 @@ namespace Vocaluxe.GameModes
|
||||
{
|
||||
protected override CSong _PrepareSong(CSong song)
|
||||
{
|
||||
if (!song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
return null;
|
||||
var newSong = new CSong(song) {Start = CGame.GetTimeFromBeats(song.Medley.StartBeat, song.BPM) - song.Medley.FadeInTime + song.Gap};
|
||||
if (newSong.Start < 0f)
|
||||
newSong.Start = 0f;
|
||||
|
||||
@@ -29,33 +29,22 @@ namespace Vocaluxe.Lib.Playlist
|
||||
{
|
||||
public class CPlaylistFile
|
||||
{
|
||||
private static readonly XmlWriterSettings _Settings = new XmlWriterSettings();
|
||||
|
||||
public string PlaylistName;
|
||||
public string PlaylistFile;
|
||||
public List<CPlaylistSong> Songs = new List<CPlaylistSong>();
|
||||
|
||||
public CPlaylistFile()
|
||||
{
|
||||
_Init();
|
||||
PlaylistName = string.Empty;
|
||||
PlaylistFile = string.Empty;
|
||||
}
|
||||
|
||||
public CPlaylistFile(string file)
|
||||
{
|
||||
_Init();
|
||||
PlaylistFile = file;
|
||||
_LoadPlaylist();
|
||||
}
|
||||
|
||||
private void _Init()
|
||||
{
|
||||
_Settings.Indent = true;
|
||||
_Settings.Encoding = Encoding.UTF8;
|
||||
_Settings.ConformanceLevel = ConformanceLevel.Document;
|
||||
}
|
||||
|
||||
public void SavePlaylist()
|
||||
{
|
||||
if (PlaylistFile == "")
|
||||
@@ -86,7 +75,7 @@ namespace Vocaluxe.Lib.Playlist
|
||||
XmlWriter writer;
|
||||
try
|
||||
{
|
||||
writer = XmlWriter.Create(PlaylistFile, _Settings);
|
||||
writer = XmlWriter.Create(PlaylistFile, CConfig.XMLSettings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -180,7 +169,11 @@ namespace Vocaluxe.Lib.Playlist
|
||||
|
||||
public void AddSong(int songID)
|
||||
{
|
||||
var song = new CPlaylistSong {SongID = songID, GameMode = CSongs.GetSong(songID).IsDuet ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL};
|
||||
var song = new CPlaylistSong
|
||||
{
|
||||
SongID = songID,
|
||||
GameMode = CSongs.GetSong(songID).IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET) ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL
|
||||
};
|
||||
|
||||
Songs.Add(song);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
|
||||
private float _FrameDuration; // frame time in s
|
||||
private float _LastDecodedTime; // time of last decoded frame
|
||||
private float _LastShownTime; // current video position
|
||||
private float _LastShownTime; // time if the last shown frame in s
|
||||
|
||||
private float _Time;
|
||||
private float _Gap;
|
||||
@@ -123,12 +123,6 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
|
||||
public bool GetFrame(ref CTexture frame, float time, out float videoTime)
|
||||
{
|
||||
if (_Paused)
|
||||
{
|
||||
videoTime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Loop)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
@@ -137,16 +131,16 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
_LoopTimer.Restart();
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(_SetTime - time) > float.Epsilon)
|
||||
else if (Math.Abs(_SetTime - time) >= 1f / 1000f) //Check 1 ms difference
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_SetTime = time;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (Math.Abs(_LastShownTime - time) < 1f / 1000 && frame != null) //Check 1 ms difference
|
||||
{
|
||||
videoTime = 0;
|
||||
videoTime = _LastShownTime;
|
||||
return true;
|
||||
}
|
||||
_UploadNewFrame(ref frame);
|
||||
@@ -185,11 +179,6 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
}
|
||||
_LastDecodedTime = _SkipTime;
|
||||
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_LastShownTime = _LastDecodedTime;
|
||||
}
|
||||
|
||||
lock (_MutexFramebuffer)
|
||||
{
|
||||
_Framebuffer.Clear();
|
||||
@@ -425,13 +414,15 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
float now = _SetTime + _Gap;
|
||||
float maxEnd = now - _FrameDuration * 2; //Get only frames younger than 2
|
||||
CFrame frame;
|
||||
bool paused = _Paused;
|
||||
while ((frame = _Framebuffer.Get()) != null)
|
||||
{
|
||||
float frameEnd = frame.Time + _FrameDuration;
|
||||
//Don't show frames that are shown during or after now
|
||||
if (frameEnd >= now)
|
||||
break; //All following frames are after that one
|
||||
|
||||
if (paused) // Don't modify anything
|
||||
break;
|
||||
_Framebuffer.SetRead();
|
||||
//Get the last(newest) possible frame and skip the rest to force in-order showing
|
||||
if (frameEnd <= maxEnd)
|
||||
@@ -455,4 +446,4 @@ namespace Vocaluxe.Lib.Video.Acinerella
|
||||
}
|
||||
#endregion Threading
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,31 +21,94 @@ namespace Vocaluxe.Lib.Video
|
||||
{
|
||||
interface IVideoDecoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes videodecoder. Got to be called before usage
|
||||
/// </summary>
|
||||
/// <returns>True on success, false if something went wrong.</returns>
|
||||
bool Init();
|
||||
|
||||
/// <summary>
|
||||
/// Close all video streams
|
||||
/// </summary>
|
||||
void CloseAll();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the file with the given file path.
|
||||
/// </summary>
|
||||
/// <param name="videoFileName">Absolute file path of the video file</param>
|
||||
/// <returns>StreamID >=0 on success or -1 on failure</returns>
|
||||
int Load(string videoFileName);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the stream with the given ID
|
||||
/// </summary>
|
||||
/// <param name="streamID">ID of the stream</param>
|
||||
/// <returns>true if stream was closed, false if stream doesn't exist or already closed</returns>
|
||||
bool Close(int streamID);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of streams currently active
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
int GetNumStreams();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the video in s
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
/// <returns>Length of the video in s</returns>
|
||||
float GetLength(int streamID);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a frame of the video and sets the current video time
|
||||
/// </summary>
|
||||
/// <param name="streamID"></param>
|
||||
/// <param name="frame"></param>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="videoTime"></param>
|
||||
/// <returns>True if frame is valid</returns>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
/// <param name="frame">Reference to already initialized video texture (from previous calls). If null, one will be created.<br/>
|
||||
/// Returns the current video frame which might be outdated if time != current (internal) video position or unchanged (even null) if none is available.</param>
|
||||
/// <param name="time">The position in s of the video you want to get a frame of. If != current (internal) video position, it will seek to get to right position.<br/>
|
||||
/// <b>Note:</b>Will be ignored for looped playback!</param>
|
||||
/// <param name="videoTime">The actual position in s of the returned frame. Should be ~ time+VideoGap</param>
|
||||
/// <returns>True if frame is valid, false: frame and videoTime might be unchanged or invalid</returns>
|
||||
bool GetFrame(int streamID, ref CTexture frame, float time, out float videoTime);
|
||||
|
||||
/// <summary>
|
||||
/// Seeks to given position
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
/// <param name="start">Position to seek to</param>
|
||||
/// <param name="gap">New video gap -> Actual position will be start+gap</param>
|
||||
/// <returns>True on success</returns>
|
||||
bool Skip(int streamID, float start, float gap);
|
||||
|
||||
/// <summary>
|
||||
/// Set if the video should be looped
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
/// <param name="loop">True if it should be looped</param>
|
||||
void SetLoop(int streamID, bool loop);
|
||||
|
||||
/// <summary>
|
||||
/// Pauses the video (no new frames will be decoded)
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
void Pause(int streamID);
|
||||
|
||||
/// <summary>
|
||||
/// Resumes a paused video
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
void Resume(int streamID);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the given video is finished
|
||||
/// </summary>
|
||||
/// <param name="streamID">Id of the stream</param>
|
||||
/// <returns>True if all frames are shown</returns>
|
||||
bool Finished(int streamID);
|
||||
|
||||
/// <summary>
|
||||
/// Do a step of the decoder in unthreaded decoders. Should be called once every frame.
|
||||
/// </summary>
|
||||
void Update();
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -28,7 +28,6 @@ using Vocaluxe.Base.Server;
|
||||
|
||||
namespace Vocaluxe
|
||||
{
|
||||
// just a small comment for the new develop branch
|
||||
static class CMainProgram
|
||||
{
|
||||
private static CSplashScreen _SplashScreen;
|
||||
@@ -75,6 +74,9 @@ namespace Vocaluxe
|
||||
// Init Log
|
||||
CLog.Init();
|
||||
|
||||
if (!CProgrammHelper.CheckRequirements())
|
||||
return;
|
||||
|
||||
CMain.Init();
|
||||
CSettings.CreateFolders();
|
||||
Application.DoEvents();
|
||||
|
||||
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
|
||||
// Revision
|
||||
//
|
||||
|
||||
[assembly: AssemblyVersion("0.3.0.81")]
|
||||
[assembly: AssemblyFileVersion("0.3.0.81")]
|
||||
[assembly: AssemblyVersion("0.3.0.82")]
|
||||
[assembly: AssemblyFileVersion("0.3.0.82")]
|
||||
@@ -200,7 +200,7 @@ namespace Vocaluxe.Screens
|
||||
CGame.ClearSongs();
|
||||
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
if (CSongs.AllSongs[songNr].IsDuet)
|
||||
if (CSongs.AllSongs[songNr].IsGameModeAvailable(EGameMode.TR_GAMEMODE_DUET))
|
||||
gm = EGameMode.TR_GAMEMODE_DUET;
|
||||
|
||||
CGame.AddSong(songNr, gm);
|
||||
|
||||
@@ -22,6 +22,7 @@ using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
namespace Vocaluxe.Screens
|
||||
{
|
||||
@@ -597,6 +598,8 @@ namespace Vocaluxe.Screens
|
||||
_CheckMics();
|
||||
_CheckPlayers();
|
||||
|
||||
CSong firstSong = CGame.GetSong(0);
|
||||
|
||||
for (int i = 0; i < CSettings.MaxNumPlayer; i++)
|
||||
{
|
||||
_Statics[_StaticPlayerAvatar[i]].Texture = CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID) ?
|
||||
@@ -607,8 +610,9 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Clear();
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Visible = i + 1 <= CGame.NumPlayer;
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(0).DuetPart1);
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(CGame.GetSong(0).DuetPart2);
|
||||
|
||||
for (int j = 0; j < firstSong.Notes.VoiceCount; j++)
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(firstSong.Notes.VoiceNames[j]);
|
||||
_SelectSlides[_SelectSlideDuetPlayer[i]].Selection = i % 2;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -298,10 +298,8 @@ namespace Vocaluxe.Screens
|
||||
string name = CProfiles.GetPlayerName(players[p].ProfileID, p);
|
||||
if (song != null && song.IsDuet)
|
||||
{
|
||||
if (players[p].VoiceNr == 0 && song.DuetPart1 != "Part 1")
|
||||
name += " (" + song.DuetPart1 + ")";
|
||||
else if (players[p].VoiceNr == 1 && song.DuetPart2 != "Part 2")
|
||||
name += " (" + song.DuetPart2 + ")";
|
||||
if (song.Notes.VoiceNames.IsSet(players[p].VoiceNr))
|
||||
name += " (" + song.Notes.VoiceNames[players[p].VoiceNr] + ")";
|
||||
}
|
||||
_Texts[_TextNames[p, CGame.NumPlayer - 1]].Text = name;
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ namespace Vocaluxe.Screens
|
||||
_LoadNextSong();
|
||||
|
||||
_UpdateSongText();
|
||||
_UpdateDuetText();
|
||||
_UpdateDuetNames();
|
||||
if (_FadeOut)
|
||||
return true;
|
||||
|
||||
@@ -387,12 +387,8 @@ namespace Vocaluxe.Screens
|
||||
|
||||
for (int p = 0; p < CGame.NumPlayer; p++)
|
||||
{
|
||||
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
|
||||
if (CGame.Players[p].Points < 10000)
|
||||
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString("0000");
|
||||
else
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString("00000");
|
||||
string fmtString = (CGame.Players[p].Points < 10000) ? "0000" : "00000";
|
||||
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString(fmtString);
|
||||
}
|
||||
|
||||
if (_CurrentVideo != -1 && !_FadeOut && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON)
|
||||
@@ -607,12 +603,12 @@ namespace Vocaluxe.Screens
|
||||
_FinishTime = song.Finish;
|
||||
_TimeToFirstNote = 0f;
|
||||
_TimeToFirstNoteDuet = 0f;
|
||||
var duetPlayer = new int[CGame.NumPlayer];
|
||||
var voiceAssignments = new int[CGame.NumPlayer];
|
||||
if (song.IsDuet)
|
||||
{
|
||||
//Save duet-assignment before resetting
|
||||
for (int i = 0; i < duetPlayer.Length; i++)
|
||||
duetPlayer[i] = CGame.Players[i].VoiceNr;
|
||||
for (int i = 0; i < voiceAssignments.Length; i++)
|
||||
voiceAssignments[i] = CGame.Players[i].VoiceNr;
|
||||
}
|
||||
CGame.ResetPlayer();
|
||||
|
||||
@@ -634,8 +630,9 @@ namespace Vocaluxe.Screens
|
||||
|
||||
if (song.IsDuet)
|
||||
{
|
||||
_Texts[_TextDuetName1].Text = song.DuetPart1;
|
||||
_Texts[_TextDuetName2].Text = song.DuetPart2;
|
||||
//TODO: Show more than 2 voicenames
|
||||
_Texts[_TextDuetName1].Text = song.Notes.VoiceNames[0];
|
||||
_Texts[_TextDuetName2].Text = song.Notes.VoiceNames[1];
|
||||
//More than one song: Player is not assigned to line by user
|
||||
//Otherwise, this is done by CScreenNames
|
||||
if (CGame.GetNumSongs() > 1)
|
||||
@@ -646,7 +643,7 @@ namespace Vocaluxe.Screens
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < CGame.NumPlayer; i++)
|
||||
CGame.Players[i].VoiceNr = duetPlayer[i];
|
||||
CGame.Players[i].VoiceNr = voiceAssignments[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,14 +669,11 @@ namespace Vocaluxe.Screens
|
||||
NoteLines[3] = SingNotes[SingBars].AddPlayer(new SRectF(640f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[3]);
|
||||
break;
|
||||
*/
|
||||
_TimerSongText.Stop();
|
||||
_TimerSongText.Reset();
|
||||
_TimerDuetText1.Stop();
|
||||
_TimerDuetText1.Reset();
|
||||
_TimerDuetText2.Stop();
|
||||
_TimerDuetText2.Reset();
|
||||
|
||||
if (song.Notes.Voices.Length != 2)
|
||||
if (!song.IsDuet)
|
||||
_TimerSongText.Start();
|
||||
|
||||
_StartSong();
|
||||
@@ -781,7 +775,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
|
||||
_CurrentBeat = CGame.CurrentBeat;
|
||||
for (int i = 0; i < song.Notes.LinesCount; i++)
|
||||
for (int i = 0; i < song.Notes.VoiceCount; i++)
|
||||
{
|
||||
if (i > 1)
|
||||
break; // for later
|
||||
@@ -1090,10 +1084,10 @@ namespace Vocaluxe.Screens
|
||||
if (song == null || !song.NotesLoaded)
|
||||
return null;
|
||||
|
||||
var alpha = new float[song.Notes.Voices.Length * 2];
|
||||
var alpha = new float[song.Notes.VoiceCount * 2];
|
||||
float currentTime = _CurrentTime - song.Gap;
|
||||
|
||||
for (int i = 0; i < song.Notes.LinesCount; i++)
|
||||
for (int i = 0; i < song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = song.Notes.GetVoice(i);
|
||||
CSongLine[] lines = voice.Lines;
|
||||
@@ -1197,8 +1191,8 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
else
|
||||
{
|
||||
_Statics[_StaticSongText].Color.A = (3f - (t - 7f)) / 3f;
|
||||
_Texts[_TextSongName].Color.A = (3f - (t - 7f)) / 3f;
|
||||
_Statics[_StaticSongText].Color.A = 10f - t / 3f;
|
||||
_Texts[_TextSongName].Color.A = 10f - t / 3f;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1215,61 +1209,65 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
}
|
||||
|
||||
private void _UpdateDuetText()
|
||||
private void _UpdateDuetNames(CText textName, Stopwatch timer)
|
||||
{
|
||||
if (CGame.GetSong() != null)
|
||||
if (timer.IsRunning)
|
||||
{
|
||||
//Timer for first duet-part
|
||||
if (_TimerDuetText1.IsRunning)
|
||||
float t = timer.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
float t = _TimerDuetText1.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName1].Visible = true;
|
||||
textName.Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName1].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName1].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName1].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
if (t < 3f)
|
||||
textName.Color.A = t / 3f;
|
||||
else if (t < 7f)
|
||||
textName.Color.A = 1f;
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName1].Visible = false;
|
||||
_TimerDuetText1.Stop();
|
||||
}
|
||||
textName.Color.A = (10f - t) / 3f;
|
||||
}
|
||||
else if (!_TimerDuetText1.IsRunning && _TimerDuetText1.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText1.Start();
|
||||
else
|
||||
_Texts[_TextDuetName1].Visible = false;
|
||||
//Timer for second duet-part
|
||||
if (_TimerDuetText2.IsRunning)
|
||||
{
|
||||
float t = _TimerDuetText2.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName2].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
_TimerDuetText2.Stop();
|
||||
}
|
||||
textName.Visible = false;
|
||||
timer.Stop();
|
||||
}
|
||||
else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText2.Start();
|
||||
else
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
}
|
||||
else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
timer.Start();
|
||||
else
|
||||
textName.Visible = false;
|
||||
}
|
||||
|
||||
private void _UpdateDuetNames()
|
||||
{
|
||||
if (CGame.GetSong() == null)
|
||||
return;
|
||||
//Timer for first duet-part
|
||||
_UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1);
|
||||
//Timer for second duet-part
|
||||
if (_TimerDuetText2.IsRunning)
|
||||
{
|
||||
float t = _TimerDuetText2.ElapsedMilliseconds / 1000f;
|
||||
if (t < 10f)
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = true;
|
||||
|
||||
if (t < 3f)
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f;
|
||||
else if (t < 7f)
|
||||
_Texts[_TextDuetName2].Color.A = 1f;
|
||||
else
|
||||
_Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
_TimerDuetText2.Stop();
|
||||
}
|
||||
}
|
||||
else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet)
|
||||
_TimerDuetText2.Start();
|
||||
else
|
||||
_Texts[_TextDuetName2].Visible = false;
|
||||
}
|
||||
|
||||
private void _UpdateTimeLine()
|
||||
|
||||
@@ -658,7 +658,7 @@ namespace Vocaluxe.Screens
|
||||
CBackgroundMusic.Disabled = false;
|
||||
|
||||
int song = _SongMenus[_SongMenu].GetActualSelection();
|
||||
if ((CSongs.Category >= 0 || CConfig.Tabs == EOffOn.TR_CONFIG_OFF) && song >= 0 && song < CSongs.VisibleSongs.Count)
|
||||
if ((CSongs.IsInCategory || CConfig.Tabs == EOffOn.TR_CONFIG_OFF) && song >= 0 && song < CSongs.VisibleSongs.Count)
|
||||
_Texts[_TextSelection].Text = CSongs.VisibleSongs[song].Artist + " - " + CSongs.VisibleSongs[song].Title;
|
||||
else if (!CSongs.IsInCategory && song >= 0 && song < CSongs.Categories.Count)
|
||||
_Texts[_TextSelection].Text = CSongs.Categories[song].Name;
|
||||
@@ -819,9 +819,8 @@ namespace Vocaluxe.Screens
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
|
||||
CGame.AddVisibleSong(songNr, gm);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, gm))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,9 +833,8 @@ namespace Vocaluxe.Screens
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
|
||||
CGame.AddVisibleSong(songNr, gm);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, gm))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,14 +842,13 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
if ((CSongs.Category >= 0) && (songNr >= 0))
|
||||
{
|
||||
if (CSongs.VisibleSongs[songNr].Medley.Source == EMedleySource.None)
|
||||
if (!CSongs.VisibleSongs[songNr].IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
return;
|
||||
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
if (CGame.AddVisibleSong(songNr, EGameMode.TR_GAMEMODE_MEDLEY))
|
||||
CGraphics.FadeTo(EScreens.ScreenNames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,7 +1011,7 @@ namespace Vocaluxe.Screens
|
||||
if (firstLevel && !secondSort)
|
||||
{
|
||||
//TODO: What's to do with multiple tags?
|
||||
//How can we get current letter? I think we have to save it - Or is there a better method?
|
||||
//Flamefire: What? We only sorted by one tag, sorting by multiple tags (e.g. Album) will be by e.g. the first entry. That can be used here too as otherwhise it will confuse users because it jumps randomly
|
||||
ReadOnlyCollection<CSong> songs = CSongs.VisibleSongs;
|
||||
int ct = songs.Count;
|
||||
int visibleID = -1;
|
||||
@@ -1027,7 +1024,6 @@ namespace Vocaluxe.Screens
|
||||
visibleID = _FindIndex(songs, start, element => element.Artist.StartsWith(letter.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
break;
|
||||
|
||||
//TODO: Does this make sense? Maybe we should deactivate this for years? You could only jump between 1 and 2
|
||||
case ESongSorting.TR_CONFIG_YEAR:
|
||||
case ESongSorting.TR_CONFIG_DECADE:
|
||||
if (curSelected >= 0 && curSelected < ct - 1 && songs[curSelected].Year.StartsWith(letter.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
@@ -1142,26 +1138,37 @@ namespace Vocaluxe.Screens
|
||||
_Statics[_StaticOptionsBG].Visible = false;
|
||||
_Buttons[_ButtonOpenOptions].Visible = true;
|
||||
|
||||
if (CSongs.VisibleSongs.Count > 0)
|
||||
if (view == ESongOptionsView.None)
|
||||
_SongOptionsActive = false;
|
||||
else if (CSongs.IsInCategory)
|
||||
_SongOptionsActive = CSongs.VisibleSongs.Count > 0;
|
||||
else
|
||||
_SongOptionsActive = CSongs.Categories.Count > 0;
|
||||
|
||||
if (!_SongOptionsActive)
|
||||
return;
|
||||
|
||||
//Has to be done here otherwhise changed playlist names will not appear until OnShow is called!
|
||||
_UpdatePlaylistNames();
|
||||
|
||||
_Texts[_TextOptionsTitle].Visible = true;
|
||||
_Buttons[_ButtonOptionsClose].Visible = true;
|
||||
_Statics[_StaticOptionsBG].Visible = true;
|
||||
_Buttons[_ButtonOpenOptions].Visible = false;
|
||||
if (view == ESongOptionsView.Song)
|
||||
_ShowSongOptionsSong();
|
||||
else if (view == ESongOptionsView.General)
|
||||
_ShowSongOptionsGeneral();
|
||||
else if (view == ESongOptionsView.Medley)
|
||||
_ShowSongOptionsMedley();
|
||||
}
|
||||
|
||||
private void _CheckAndAddGameMode(EGameMode gameMode)
|
||||
{
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].IsGameModeAvailable(gameMode))
|
||||
{
|
||||
_SongOptionsActive = view != ESongOptionsView.None;
|
||||
|
||||
if (_SongOptionsActive)
|
||||
{
|
||||
//Has to be done here otherwhise changed playlist names will not appear until OnShow is called!
|
||||
_UpdatePlaylistNames();
|
||||
|
||||
_Texts[_TextOptionsTitle].Visible = true;
|
||||
_Buttons[_ButtonOptionsClose].Visible = true;
|
||||
_Statics[_StaticOptionsBG].Visible = true;
|
||||
_Buttons[_ButtonOpenOptions].Visible = false;
|
||||
if (view == ESongOptionsView.Song)
|
||||
_ShowSongOptionsSong();
|
||||
else if (view == ESongOptionsView.General)
|
||||
_ShowSongOptionsGeneral();
|
||||
else if (view == ESongOptionsView.Medley)
|
||||
_ShowSongOptionsMedley();
|
||||
}
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), gameMode));
|
||||
_AvailableGameModes.Add(gameMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1172,23 +1179,11 @@ namespace Vocaluxe.Screens
|
||||
lastMode = _AvailableGameModes[_SelectSlides[_SelectSlideOptionsMode].Selection];
|
||||
_AvailableGameModes.Clear();
|
||||
_SelectSlides[_SelectSlideOptionsMode].Clear();
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].IsDuet)
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_DUET));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_DUET);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_NORMAL));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_NORMAL);
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_SHORTSONG));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
}
|
||||
if (CSongs.VisibleSongs[_SongMenus[_SongMenu].GetSelectedSong()].Medley.Source != EMedleySource.None)
|
||||
{
|
||||
_SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), EGameMode.TR_GAMEMODE_MEDLEY));
|
||||
_AvailableGameModes.Add(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
}
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_NORMAL);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_DUET);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
_CheckAndAddGameMode(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
|
||||
//Set SelectSlide-Selection to last selected game-mode if possible
|
||||
for (int i = 0; i < _AvailableGameModes.Count; i++)
|
||||
{
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Vocaluxe.SongQueue
|
||||
|
||||
private bool _AddSong(int songID, EGameMode gameMode)
|
||||
{
|
||||
if (gameMode == EGameMode.TR_GAMEMODE_DUET && !CSongs.GetSong(songID).IsDuet)
|
||||
if (!CSongs.GetSong(songID).IsGameModeAvailable(gameMode))
|
||||
return false;
|
||||
|
||||
_SongQueue.Add(new SSongQueueEntry(songID, gameMode));
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
<Compile Include="Base\Server\CCommands.cs" />
|
||||
<Compile Include="Base\Server\CVocaluxeServer.cs" />
|
||||
<Compile Include="Base\Server\VocaluxeStructs.cs" />
|
||||
<Compile Include="CProgrammHelper.cs" />
|
||||
<Compile Include="CSplashScreen.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -336,4 +337,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
+6
-11
@@ -62,7 +62,6 @@ namespace VocaluxeLib
|
||||
public static string ListStrings(string[] str)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
result += str[i];
|
||||
@@ -150,6 +149,8 @@ namespace VocaluxeLib
|
||||
{
|
||||
var files = new List<string>();
|
||||
var dir = new DirectoryInfo(path);
|
||||
if (!dir.Exists)
|
||||
return files;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -169,13 +170,7 @@ namespace VocaluxeLib
|
||||
return files;
|
||||
}
|
||||
|
||||
public static bool TryParse<T>(string value, out T result)
|
||||
where T : struct
|
||||
{
|
||||
return TryParse(value, out result, false);
|
||||
}
|
||||
|
||||
public static bool TryParse<T>(string value, out T result, bool ignoreCase)
|
||||
public static bool TryParse<T>(string value, out T result, bool ignoreCase=false)
|
||||
where T : struct
|
||||
{
|
||||
result = default(T);
|
||||
@@ -208,7 +203,7 @@ namespace VocaluxeLib
|
||||
|
||||
static class CEncoding
|
||||
{
|
||||
public static Encoding GetEncoding(string encodingName)
|
||||
public static Encoding GetEncoding(this string encodingName)
|
||||
{
|
||||
switch (encodingName)
|
||||
{
|
||||
@@ -223,11 +218,11 @@ namespace VocaluxeLib
|
||||
case "UTF8":
|
||||
return Encoding.UTF8;
|
||||
default:
|
||||
return Encoding.UTF8;
|
||||
return Encoding.Default;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetEncodingName(Encoding enc)
|
||||
public static string GetEncodingName(this Encoding enc)
|
||||
{
|
||||
string result = "UTF8";
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace VocaluxeLib
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resizes the given list to the given size. Removes elements or adds default values
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public static void Resize<T>(this List<T> list, int size, T defaultValue = default(T))
|
||||
{
|
||||
int curSize = list.Count;
|
||||
if (size < curSize)
|
||||
list.RemoveRange(size, curSize - size);
|
||||
else if (size > curSize)
|
||||
list.AddRange(Enumerable.Repeat(defaultValue, size - curSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the list at least the given size adding the given default values.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public static void EnsureSize<T>(this List<T> list, int size, T defaultValue)
|
||||
{
|
||||
int curSize = list.Count;
|
||||
if (size > curSize)
|
||||
list.AddRange(Enumerable.Repeat(defaultValue, size - curSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the list at least the given size adding a new instance of T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="size"></param>
|
||||
public static void EnsureSize<T>(this List<T> list, int size) where T : new()
|
||||
{
|
||||
if (size > list.Count)
|
||||
list.Add(new T());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all set bits starting from lowest (Bit 0)
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<int> GetSetBits(this int value)
|
||||
{
|
||||
var result = new List<int>();
|
||||
int curBit = 0;
|
||||
//Evaluate as bitset
|
||||
while (value > 0)
|
||||
{
|
||||
if ((value & 1) != 0)
|
||||
result.Add(curBit);
|
||||
value >>= 1;
|
||||
curBit++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool ContainsIgnoreCase(this string value, string other)
|
||||
{
|
||||
return value.IndexOf(other, StringComparison.CurrentCultureIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
public static string TrimMultipleWs(this string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
int start = 0;
|
||||
int len = value.Length;
|
||||
while (value[start] == ' ')
|
||||
{
|
||||
start++;
|
||||
if (start >= len)
|
||||
return "";
|
||||
}
|
||||
if (start > 0)
|
||||
start--;
|
||||
int end = --len;
|
||||
while (value[end] == ' ')
|
||||
end--;
|
||||
if (end < len)
|
||||
end++;
|
||||
if (end - start < len)
|
||||
value = value.Substring(start, end - start + 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts value to a string in fixed point notation using invariant formating (english style decimal point)
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be converted</param>
|
||||
/// <returns>String representation of value</returns>
|
||||
public static string ToInvariantString(this float value)
|
||||
{
|
||||
return value.ToString("F", NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -19,6 +19,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Game;
|
||||
using VocaluxeLib.Menu;
|
||||
@@ -29,6 +30,8 @@ namespace VocaluxeLib
|
||||
{
|
||||
public interface IConfig
|
||||
{
|
||||
EOffOn GetSaveModifiedSongs();
|
||||
|
||||
void SetBackgroundMusicVolume(int newVolume);
|
||||
int GetBackgroundMusicVolume();
|
||||
|
||||
@@ -45,13 +48,18 @@ namespace VocaluxeLib
|
||||
|
||||
int GetCoverSize();
|
||||
|
||||
IEnumerable<string> GetSongFolder();
|
||||
IEnumerable<string> GetSongFolders();
|
||||
ESongSorting GetSongSorting();
|
||||
EOffOn GetTabs();
|
||||
EOffOn GetIgnoreArticles();
|
||||
|
||||
bool IsMicConfigured(int playerNr);
|
||||
int GetMaxNumMics();
|
||||
|
||||
/// <summary>
|
||||
/// Get the uniform settings for writing XML files. ALWAYS use this!
|
||||
/// </summary>
|
||||
XmlWriterSettings GetXMLSettings();
|
||||
}
|
||||
|
||||
public interface ISettings
|
||||
@@ -179,6 +187,7 @@ namespace VocaluxeLib
|
||||
double GetRandomDouble();
|
||||
|
||||
float GetTimeFromBeats(float beat, float bpm);
|
||||
float GetBeatFromTime(float time, float bpm, float gap);
|
||||
|
||||
void AddSong(int songID, EGameMode gameMode);
|
||||
void Reset();
|
||||
@@ -204,7 +213,8 @@ namespace VocaluxeLib
|
||||
int GetNumSongs();
|
||||
int GetNumSongsVisible();
|
||||
int GetNumCategories();
|
||||
int NumSongsInCategory(int categoryIndex);
|
||||
int GetNumSongsInCategory(int categoryIndex);
|
||||
int GetNumSongsNotSungInCategory(int categoryIndex);
|
||||
bool IsInCategory();
|
||||
|
||||
int GetCurrentCategoryIndex();
|
||||
|
||||
+55
-108
@@ -23,15 +23,6 @@ using VocaluxeLib.Songs;
|
||||
|
||||
namespace VocaluxeLib.Menu
|
||||
{
|
||||
struct SNote
|
||||
{
|
||||
public string Text;
|
||||
public int StartBeat;
|
||||
public int EndBeat;
|
||||
public int Duration;
|
||||
public ENoteType Type;
|
||||
}
|
||||
|
||||
struct SThemeLyrics
|
||||
{
|
||||
public string Name;
|
||||
@@ -46,7 +37,10 @@ namespace VocaluxeLib.Menu
|
||||
private SThemeLyrics _Theme;
|
||||
private bool _ThemeLoaded;
|
||||
|
||||
private readonly List<SNote> _Notes;
|
||||
/// <summary>
|
||||
/// Holds a reference to Songline. DO NOT MODIFY
|
||||
/// </summary>
|
||||
private CSongLine _Line;
|
||||
private CText _Text;
|
||||
|
||||
private float _X;
|
||||
@@ -109,7 +103,7 @@ namespace VocaluxeLib.Menu
|
||||
_MaxW = 1f;
|
||||
_H = 1f;
|
||||
_Width = 1f;
|
||||
_Notes = new List<SNote>();
|
||||
_Line = new CSongLine();
|
||||
_Text = new CText(_PartyModeID);
|
||||
|
||||
LyricStyle = ELyricStyle.Fill;
|
||||
@@ -201,28 +195,27 @@ namespace VocaluxeLib.Menu
|
||||
|
||||
public void SetLine(CSongLine line)
|
||||
{
|
||||
_Notes.Clear();
|
||||
|
||||
_Line = line;
|
||||
_Width = 0f;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
var n = new SNote {Text = note.Text, StartBeat = note.StartBeat, EndBeat = note.EndBeat, Duration = note.Duration, Type = note.NoteType};
|
||||
|
||||
_Text.Text = note.Text;
|
||||
_Text.Style = EStyle.Bold;
|
||||
|
||||
if (n.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_Width += rect.Width;
|
||||
_Notes.Add(n);
|
||||
_SetText(note);
|
||||
_Width += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
private void _SetText(CSongNote note)
|
||||
{
|
||||
_Text.Text = note.Text;
|
||||
_Text.Style = EStyle.Bold;
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_Notes.Clear();
|
||||
_Line = new CSongLine();
|
||||
}
|
||||
|
||||
public float GetCurrentLyricPosX()
|
||||
@@ -260,15 +253,10 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
float x = _X - _Width / 2;
|
||||
|
||||
foreach (SNote note in _Notes)
|
||||
foreach (CSongNote note in _Line.Notes)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = note.Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
_SetText(note);
|
||||
|
||||
if (currentBeat >= note.StartBeat)
|
||||
{
|
||||
@@ -276,9 +264,8 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
_Text.Color = _ColorProcessed;
|
||||
|
||||
|
||||
float diff = note.EndBeat - note.StartBeat;
|
||||
if (Math.Abs(diff) < float.Epsilon)
|
||||
int diff = note.EndBeat - note.StartBeat;
|
||||
if (diff <= 0)
|
||||
_Text.Draw(0f, 1f);
|
||||
else
|
||||
{
|
||||
@@ -299,7 +286,7 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,37 +295,27 @@ namespace VocaluxeLib.Menu
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
//find last active note
|
||||
int lastNote = -1;
|
||||
for (int i = 0; i < _Notes.Count; i++)
|
||||
{
|
||||
if (currentBeat >= _Notes[i].StartBeat)
|
||||
lastNote = i;
|
||||
}
|
||||
int lastNote = _Line.FindPreviousNote((int)currentBeat);
|
||||
|
||||
int zoomNote = -1;
|
||||
int endBeat = -1;
|
||||
float zoomx = 0f;
|
||||
|
||||
for (int note = 0; note < _Notes.Count; note++)
|
||||
for (int note = 0; note < _Line.Notes.Length; note++)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = _Notes[note].Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_SetText(_Line.Notes[note]);
|
||||
|
||||
if (_Notes[note].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
if (currentBeat >= _Notes[note].StartBeat)
|
||||
if (currentBeat >= _Line.Notes[note].StartBeat)
|
||||
{
|
||||
int endbeat = _Notes[note].EndBeat;
|
||||
if (note < _Notes.Count - 1)
|
||||
endbeat = _Notes[note + 1].StartBeat - 1;
|
||||
int curEndBeat = _Line.Notes[note].EndBeat;
|
||||
if (note < _Line.Notes.Length - 1)
|
||||
curEndBeat = _Line.Notes[note + 1].StartBeat - 1;
|
||||
|
||||
if (currentBeat <= endbeat)
|
||||
if (currentBeat <= curEndBeat)
|
||||
{
|
||||
zoomNote = note;
|
||||
endBeat = endbeat;
|
||||
endBeat = curEndBeat;
|
||||
zoomx = _Text.X;
|
||||
}
|
||||
else
|
||||
@@ -356,49 +333,37 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
|
||||
if (zoomNote > -1)
|
||||
{
|
||||
if (_Notes[zoomNote].Duration == 0)
|
||||
return;
|
||||
|
||||
_Text.X = zoomx;
|
||||
_Text.Text = _Notes[zoomNote].Text;
|
||||
_Text.Color = _ColorProcessed;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_SetText(_Line.Notes[zoomNote]);
|
||||
|
||||
if (_Notes[zoomNote].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
float diff = endBeat - _Notes[zoomNote].StartBeat;
|
||||
float diff = endBeat - _Line.Notes[zoomNote].StartBeat;
|
||||
if (diff <= 0f)
|
||||
diff = 1f;
|
||||
|
||||
float p = (currentBeat - _Notes[zoomNote].StartBeat) / diff;
|
||||
float p = (currentBeat - _Line.Notes[zoomNote].StartBeat) / diff;
|
||||
if (p > 1f)
|
||||
p = 1f;
|
||||
|
||||
p = 1f - p;
|
||||
|
||||
float ty = _Text.Y;
|
||||
float tx = _Text.X;
|
||||
float th = _Text.Height;
|
||||
float tz = _Text.Z;
|
||||
|
||||
SRectF normalRect = _Text.Rect;
|
||||
_Text.Height += _Text.Height * p * 0.4f;
|
||||
RectangleF rectz = CBase.Fonts.GetTextBounds(_Text);
|
||||
_Text.X -= (rectz.Width - rect.Width) / 2f;
|
||||
_Text.Y -= (rectz.Height - rect.Height) / 2f;
|
||||
_Text.X -= (_Text.Rect.W - normalRect.W) / 2f;
|
||||
_Text.Y -= (_Text.Rect.W - normalRect.H) / 2f;
|
||||
_Text.Z -= 0.1f;
|
||||
|
||||
_Text.Draw();
|
||||
|
||||
_Text.Y = ty;
|
||||
_Text.X = tx;
|
||||
_Text.Height = th;
|
||||
_Text.Z = tz;
|
||||
}
|
||||
@@ -408,15 +373,10 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
foreach (SNote note in _Notes)
|
||||
foreach (CSongNote note in _Line.Notes)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = note.Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
|
||||
if (note.Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
_SetText(note);
|
||||
|
||||
if (currentBeat >= note.StartBeat)
|
||||
{
|
||||
@@ -430,7 +390,7 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,29 +399,23 @@ namespace VocaluxeLib.Menu
|
||||
float x = _X - _Width / 2; // most left position
|
||||
|
||||
//find last active note
|
||||
int lastNote = -1;
|
||||
for (int i = 0; i < _Notes.Count; i++)
|
||||
{
|
||||
if (currentBeat >= _Notes[i].StartBeat)
|
||||
lastNote = i;
|
||||
}
|
||||
int lastNote = _Line.FindPreviousNote((int)currentBeat);
|
||||
|
||||
int jumpNote = -1;
|
||||
float jumpx = 0f;
|
||||
|
||||
for (int note = 0; note < _Notes.Count; note++)
|
||||
for (int note = 0; note < _Line.Notes.Length; note++)
|
||||
{
|
||||
_Text.X = x;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_Text.Text = _Notes[note].Text;
|
||||
RectangleF rect = CBase.Fonts.GetTextBounds(_Text);
|
||||
_SetText(_Line.Notes[note]);
|
||||
|
||||
if (_Notes[note].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
if (currentBeat >= _Notes[note].StartBeat)
|
||||
if (currentBeat >= _Line.Notes[note].StartBeat)
|
||||
{
|
||||
if (currentBeat <= _Notes[note].EndBeat)
|
||||
int curEndBeat = _Line.Notes[note].EndBeat;
|
||||
if (note < _Line.Notes.Length - 1)
|
||||
curEndBeat = _Line.Notes[note + 1].StartBeat - 1;
|
||||
|
||||
if (currentBeat <= curEndBeat)
|
||||
{
|
||||
jumpNote = note;
|
||||
jumpx = _Text.X;
|
||||
@@ -481,27 +435,20 @@ namespace VocaluxeLib.Menu
|
||||
_Text.Draw();
|
||||
}
|
||||
|
||||
x += rect.Width;
|
||||
x += _Text.Rect.W;
|
||||
}
|
||||
|
||||
if (jumpNote < 0)
|
||||
return;
|
||||
if (_Notes[jumpNote].Duration == 0)
|
||||
return;
|
||||
|
||||
_Text.X = jumpx;
|
||||
_Text.Text = _Notes[jumpNote].Text;
|
||||
_Text.Color = _ColorProcessed;
|
||||
_Text.Style = EStyle.Bold;
|
||||
_SetText(_Line.Notes[jumpNote]);
|
||||
|
||||
if (_Notes[jumpNote].Type == ENoteType.Freestyle)
|
||||
_Text.Style = EStyle.BoldItalic;
|
||||
|
||||
int diff = _Notes[jumpNote].EndBeat - _Notes[jumpNote].StartBeat;
|
||||
int diff = _Line.Notes[jumpNote].EndBeat - _Line.Notes[jumpNote].StartBeat;
|
||||
if (diff <= 0)
|
||||
diff = 1;
|
||||
|
||||
float p = 1f - (currentBeat - _Notes[jumpNote].StartBeat) / diff;
|
||||
float p = 1f - (currentBeat - _Line.Notes[jumpNote].StartBeat) / diff;
|
||||
|
||||
if (Math.Abs(p) < float.Epsilon)
|
||||
_Text.Draw();
|
||||
|
||||
@@ -196,10 +196,9 @@ namespace VocaluxeLib.Menu
|
||||
if (_ThemePath == "")
|
||||
return;
|
||||
|
||||
var settings = new XmlWriterSettings {Indent = true, Encoding = Encoding.UTF8, ConformanceLevel = ConformanceLevel.Document};
|
||||
|
||||
string file = Path.Combine(_ThemePath, ThemeName + ".xml");
|
||||
using (XmlWriter writer = XmlWriter.Create(file, settings))
|
||||
using (XmlWriter writer = XmlWriter.Create(file, CBase.Config.GetXMLSettings()))
|
||||
{
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("root");
|
||||
|
||||
@@ -407,9 +407,9 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
if ((i + offset * _Tiles.Count) < _VisibleProfiles.Count)
|
||||
{
|
||||
_Tiles[i].Avatar.Texture = CBase.Profiles.GetProfiles()[_VisibleProfiles[i + offset * _Tiles.Count]].Avatar.Texture;
|
||||
_Tiles[i].Avatar.Texture = CBase.Profiles.GetAvatar(_VisibleProfiles[i + offset * _Tiles.Count]);
|
||||
_Tiles[i].Avatar.Color = new SColorF(1, 1, 1, 1);
|
||||
_Tiles[i].Name.Text = CBase.Profiles.GetProfiles()[_VisibleProfiles[i + offset * _Tiles.Count]].PlayerName;
|
||||
_Tiles[i].Name.Text = CBase.Profiles.GetPlayerName(_VisibleProfiles[i + offset * _Tiles.Count]); ;
|
||||
_Tiles[i].ProfileID = _VisibleProfiles[i + offset * _Tiles.Count];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace VocaluxeLib.Menu
|
||||
{
|
||||
private class CPlaylistElementContent
|
||||
{
|
||||
public EGameMode[] Modes;
|
||||
public IList<EGameMode> Modes;
|
||||
public int SongID;
|
||||
public EGameMode Mode;
|
||||
}
|
||||
@@ -971,11 +971,11 @@ namespace VocaluxeLib.Menu
|
||||
|
||||
if (!mouseEvent.LBH && DragAndDropSongID != -1)
|
||||
{
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
CSong song = CBase.Songs.GetSongByID(DragAndDropSongID);
|
||||
|
||||
if (song != null)
|
||||
{
|
||||
var gm = EGameMode.TR_GAMEMODE_NORMAL;
|
||||
if (song.IsDuet)
|
||||
gm = EGameMode.TR_GAMEMODE_DUET;
|
||||
|
||||
@@ -1220,7 +1220,7 @@ namespace VocaluxeLib.Menu
|
||||
string t1 = CBase.Language.Translate(_Theme.Text1.Text).Replace("%a", song.Artist).Replace("%t", song.Title);
|
||||
_PlaylistElements[i].Text1.Text = /*(Offset + i + 1) + ") " + */ t1; //TODO: Add text field for the number
|
||||
_PlaylistElements[i].SelectSlide.Clear();
|
||||
for (int g = 0; g < pec.Modes.Length; g++)
|
||||
for (int g = 0; g < pec.Modes.Count; g++)
|
||||
{
|
||||
_PlaylistElements[i].SelectSlide.AddValue(Enum.GetName(typeof(EGameMode), pec.Modes[g]));
|
||||
if (pec.Modes[g] == pec.Mode)
|
||||
|
||||
@@ -422,7 +422,7 @@ namespace VocaluxeLib.Menu
|
||||
writer.WriteElementString("Align", Enum.GetName(typeof(EAlignment), Align));
|
||||
|
||||
writer.WriteComment("<ResizeAlign>: Text align vertical (on downsizing): " + CHelper.ListStrings(Enum.GetNames(typeof(EHAlignment))));
|
||||
writer.WriteElementString("HAlign", Enum.GetName(typeof(EHAlignment), ResizeAlign));
|
||||
writer.WriteElementString("ResizeAlign", Enum.GetName(typeof(EHAlignment), ResizeAlign));
|
||||
|
||||
writer.WriteComment("<Style>: Text style: " + CHelper.ListStrings(Enum.GetNames(typeof(EStyle))));
|
||||
writer.WriteElementString("Style", Enum.GetName(typeof(EStyle), Style));
|
||||
@@ -561,7 +561,7 @@ namespace VocaluxeLib.Menu
|
||||
float y = Y;
|
||||
RectangleF bounds = CBase.Fonts.GetTextBounds(this);
|
||||
|
||||
if (bounds.Width > MaxWidth && MaxWidth > 0f && bounds.Width > 0f)
|
||||
if (MaxWidth > 0f && bounds.Width > MaxWidth && bounds.Width > 0f)
|
||||
{
|
||||
float factor = MaxWidth / bounds.Width;
|
||||
float step = h * (1 - factor);
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
int nr = 1;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
if (note.NoteType != ENoteType.Freestyle)
|
||||
if (note.Type != ENoteType.Freestyle)
|
||||
{
|
||||
float width = note.Duration / beats * w;
|
||||
|
||||
@@ -334,7 +334,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
_DrawNoteBG(rect, color, 1f, _PlayerNotes[n].Timer);
|
||||
_DrawNote(rect, new SColorF(5f, 5f, 5f, 0.7f * _PlayerNotes[n].Alpha), 0.7f);
|
||||
|
||||
if (note.NoteType == ENoteType.Golden)
|
||||
if (note.Type == ENoteType.Golden)
|
||||
{
|
||||
_AddGoldenNote(rect, n, nr);
|
||||
nr++;
|
||||
@@ -386,7 +386,7 @@ namespace VocaluxeLib.Menu.SingNotes
|
||||
|
||||
_DrawNote(rect, color, f);
|
||||
|
||||
if (note.EndBeat >= CBase.Game.GetRecordedBeat() && note.Hit && note.HitNote.NoteType == ENoteType.Golden)
|
||||
if (note.EndBeat >= CBase.Game.GetRecordedBeat() && note.Hit && note.HitNote.Type == ENoteType.Golden)
|
||||
{
|
||||
var re = new SRectF(rect) {W = (CBase.Game.GetMidRecordedBeat() - note.StartBeat) / beats * w};
|
||||
_AddFlare(re, n);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public SRectF Rect
|
||||
{
|
||||
get { return _SongMenu.GetRect(); }
|
||||
get { return _SongMenu.Rect; }
|
||||
}
|
||||
|
||||
#region ISongMenu
|
||||
@@ -156,11 +156,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
_SongMenu.SetVisible(visible);
|
||||
}
|
||||
|
||||
public SRectF GetRect()
|
||||
{
|
||||
return _SongMenu.GetRect();
|
||||
}
|
||||
|
||||
public bool IsSmallView()
|
||||
{
|
||||
return _SongMenu.IsSmallView();
|
||||
|
||||
@@ -22,6 +22,7 @@ using System.IO;
|
||||
using System.Xml;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.PartyModes;
|
||||
using VocaluxeLib.Songs;
|
||||
|
||||
namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
@@ -98,106 +99,40 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
protected SThemeSongMenu _Theme;
|
||||
private bool _ThemeLoaded;
|
||||
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
private readonly Stopwatch _VideoFadeTimer = new Stopwatch();
|
||||
private readonly List<int> _Streams = new List<int>();
|
||||
private int _Actsong = -1;
|
||||
private int _Actsongstream = -1;
|
||||
protected CTexture _Vidtex;
|
||||
|
||||
protected bool _Initialized;
|
||||
protected int _LastKnownNumSongs;
|
||||
protected int _LastKnownCategory = -1;
|
||||
|
||||
protected SRectF _Rect;
|
||||
protected SColorF _Color;
|
||||
|
||||
private int _SelectedInternal = -1;
|
||||
private int _SelectedPending = -1;
|
||||
protected long _PendingTime = 500L;
|
||||
|
||||
private int _LockedInternal = -1;
|
||||
protected bool _Active;
|
||||
|
||||
protected float _MaxVolume = 100f;
|
||||
|
||||
protected int _PreviewSelected
|
||||
//the real selected song for singing
|
||||
protected int _Locked { get; set; }
|
||||
|
||||
private int _PreviewIdInternal = -1;
|
||||
protected virtual int _PreviewId
|
||||
{
|
||||
//for preview only
|
||||
get
|
||||
{
|
||||
if ((_SelectedInternal != _SelectedPending) && (_Timer.ElapsedMilliseconds >= _PendingTime))
|
||||
{
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
_SelectedInternal = _SelectedPending;
|
||||
}
|
||||
return _SelectedInternal;
|
||||
}
|
||||
get { return _PreviewIdInternal; }
|
||||
set
|
||||
{
|
||||
if (value == -1)
|
||||
{
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
|
||||
_SelectedInternal = -1;
|
||||
_SelectedPending = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((value != _SelectedInternal) && (value != _SelectedPending))
|
||||
{
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
|
||||
_SelectedPending = value;
|
||||
}
|
||||
|
||||
if ((value == _SelectedPending) && ((_Timer.ElapsedMilliseconds >= _PendingTime) || (_SelectedInternal == -1)))
|
||||
{
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
_SelectedInternal = _SelectedPending;
|
||||
}
|
||||
//Do this first, otherwhise song will restart
|
||||
_PlaySong(value);
|
||||
_PreviewIdInternal = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected void _SetSelectedNow()
|
||||
{
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
_SelectedInternal = _SelectedPending;
|
||||
}
|
||||
protected int _PreviewSongStream { get; private set; }
|
||||
|
||||
protected int _Locked
|
||||
{
|
||||
//the real selected song for singing
|
||||
get { return _LockedInternal; }
|
||||
set { _LockedInternal = value; }
|
||||
}
|
||||
protected int _PreviewVideoStream { get; private set; }
|
||||
|
||||
protected int _SongStream
|
||||
{
|
||||
get { return _Actsongstream; }
|
||||
}
|
||||
|
||||
protected int _Video { get; private set; }
|
||||
|
||||
protected int _ActSong
|
||||
{
|
||||
get { return _Actsong; }
|
||||
}
|
||||
|
||||
public SRectF Rect
|
||||
{
|
||||
get { return _Rect; }
|
||||
}
|
||||
|
||||
public SRectF GetRect()
|
||||
{
|
||||
return _Rect;
|
||||
}
|
||||
public SRectF Rect { get; protected set; }
|
||||
|
||||
public SColorF Color
|
||||
{
|
||||
@@ -206,7 +141,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public virtual int GetActualSelection()
|
||||
{
|
||||
return _Actsong;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private bool _Selected;
|
||||
@@ -236,7 +171,9 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
protected CSongMenuFramework(int partyModeID)
|
||||
{
|
||||
_PartyModeID = partyModeID;
|
||||
_Video = -1;
|
||||
_PreviewVideoStream = -1;
|
||||
_PreviewSongStream = -1;
|
||||
_Locked = -1;
|
||||
_Theme = new SThemeSongMenu
|
||||
{
|
||||
SongMenuTileBoard =
|
||||
@@ -425,7 +362,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public void UpdateRect(SRectF rect)
|
||||
{
|
||||
_Rect = rect;
|
||||
Rect = rect;
|
||||
Init();
|
||||
}
|
||||
|
||||
@@ -434,23 +371,20 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if (!_Initialized)
|
||||
return;
|
||||
|
||||
if (_Actsong != _PreviewSelected)
|
||||
_SelectSong(_PreviewSelected);
|
||||
|
||||
if (_Streams.Count <= 0 || _Video == -1)
|
||||
if (_Streams.Count <= 0 || _PreviewVideoStream == -1)
|
||||
return;
|
||||
|
||||
if (CBase.Video.IsFinished(_Video) || CBase.Sound.IsFinished(_Actsongstream))
|
||||
if (CBase.Video.IsFinished(_PreviewVideoStream) || CBase.Sound.IsFinished(_PreviewSongStream))
|
||||
{
|
||||
CBase.Video.Close(_Video);
|
||||
_Video = -1;
|
||||
CBase.Video.Close(_PreviewVideoStream);
|
||||
_PreviewVideoStream = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
float time = CBase.Sound.GetPosition(_Actsongstream);
|
||||
float time = CBase.Sound.GetPosition(_PreviewSongStream);
|
||||
|
||||
float vtime;
|
||||
if (CBase.Video.GetFrame(_Video, ref _Vidtex, time, out vtime))
|
||||
if (CBase.Video.GetFrame(_PreviewVideoStream, ref _Vidtex, time, out vtime))
|
||||
{
|
||||
if (_Vidtex != null)
|
||||
{
|
||||
@@ -467,25 +401,14 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
public virtual void OnShow()
|
||||
{
|
||||
_Actsongstream = -1;
|
||||
_PreviewSongStream = -1;
|
||||
_Vidtex = null;
|
||||
ApplyVolume(CBase.Config.GetPreviewMusicVolume());
|
||||
}
|
||||
|
||||
public virtual void OnHide()
|
||||
{
|
||||
foreach (int stream in _Streams)
|
||||
CBase.Sound.FadeAndStop(stream, 0f, 0.75f);
|
||||
_Streams.Clear();
|
||||
|
||||
CBase.Video.Close(_Video);
|
||||
_Video = -1;
|
||||
|
||||
CBase.Drawing.RemoveTexture(ref _Vidtex);
|
||||
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
_SelectedInternal = _SelectedPending;
|
||||
_Reset();
|
||||
}
|
||||
|
||||
public virtual void HandleInput(ref SKeyEvent keyEvent, SScreenSongOptions songOptions) {}
|
||||
@@ -497,7 +420,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if (!_Initialized || !_Visible)
|
||||
return;
|
||||
|
||||
if (_Video != -1)
|
||||
if (_PreviewVideoStream != -1)
|
||||
CBase.Drawing.DrawTexture(_Vidtex, new SRectF(0, 0, 1280, 720, 0));
|
||||
}
|
||||
|
||||
@@ -570,9 +493,9 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
if (!_Initialized)
|
||||
return false;
|
||||
if (CBase.Songs.IsInCategory() || _PreviewSelected < 0 || _PreviewSelected >= CBase.Songs.GetNumCategories())
|
||||
if (CBase.Songs.IsInCategory() || _PreviewId < 0 || _PreviewId >= CBase.Songs.GetNumCategories())
|
||||
return false;
|
||||
_EnterCategory(_PreviewSelected);
|
||||
_EnterCategory(_PreviewId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -600,52 +523,44 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
CBase.Songs.SetCategory(-1);
|
||||
}
|
||||
|
||||
public void ApplyVolume()
|
||||
private void _PlaySong(int nr)
|
||||
{
|
||||
CBase.Sound.SetStreamVolume(_Actsongstream, CBase.Config.GetPreviewMusicVolume());
|
||||
}
|
||||
|
||||
protected void _SelectSong(int nr)
|
||||
{
|
||||
if (CBase.Songs.IsInCategory() && (CBase.Songs.GetNumSongsVisible() > 0) && (nr >= 0) && ((_Actsong != nr) || (_Streams.Count == 0)))
|
||||
if (CBase.Songs.IsInCategory() && (_PreviewId != nr || _Streams.Count == 0))
|
||||
{
|
||||
_Streams.ForEach(soundStream => CBase.Sound.FadeAndStop(soundStream, 0f, 1f));
|
||||
_Streams.Clear();
|
||||
_Reset();
|
||||
|
||||
CBase.Video.Close(_Video);
|
||||
_Video = -1;
|
||||
CSong song = CBase.Songs.GetVisibleSong(nr);
|
||||
if (song == null)
|
||||
return;
|
||||
|
||||
CBase.Drawing.RemoveTexture(ref _Vidtex);
|
||||
|
||||
_Actsong = nr;
|
||||
if (_Actsong >= CBase.Songs.GetNumSongsVisible())
|
||||
_Actsong = 0;
|
||||
|
||||
|
||||
int stream = CBase.Sound.Load(Path.Combine(CBase.Songs.GetVisibleSong(_Actsong).Folder, CBase.Songs.GetVisibleSong(_Actsong).MP3FileName), true);
|
||||
int stream = CBase.Sound.Load(Path.Combine(song.Folder, song.MP3FileName), true);
|
||||
CBase.Sound.SetStreamVolumeMax(stream, _MaxVolume);
|
||||
CBase.Sound.SetStreamVolume(stream, 0f);
|
||||
|
||||
float startposition = CBase.Songs.GetVisibleSong(_Actsong).PreviewStart;
|
||||
float startposition = song.Preview.StartTime;
|
||||
float length = CBase.Sound.GetLength(stream);
|
||||
|
||||
if (Math.Abs(startposition) < 0.001)
|
||||
startposition = CBase.Sound.GetLength(stream) / 4f;
|
||||
if (song.Preview.Source == EDataSource.None)
|
||||
startposition = length / 4f;
|
||||
else if (startposition > length - 5f)
|
||||
startposition = Math.Max(0f, Math.Min(length / 4f, length - 5f));
|
||||
|
||||
if (startposition >= 0.5f)
|
||||
startposition -= 0.5f;
|
||||
|
||||
CBase.Sound.SetPosition(stream, startposition);
|
||||
CBase.Sound.Play(stream);
|
||||
CBase.Sound.SetStreamVolumeMax(stream, CBase.Config.GetPreviewMusicVolume());
|
||||
CBase.Sound.Fade(stream, 100f, 3f);
|
||||
_Streams.Add(stream);
|
||||
_Actsongstream = stream;
|
||||
_PreviewSongStream = stream;
|
||||
|
||||
if (CBase.Songs.GetVisibleSong(_Actsong).VideoFileName != "" && CBase.Config.GetVideoPreview() == EOffOn.TR_CONFIG_ON)
|
||||
if (song.VideoFileName != "" && CBase.Config.GetVideoPreview() == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
_Video = CBase.Video.Load(Path.Combine(CBase.Songs.GetVisibleSong(_Actsong).Folder, CBase.Songs.GetVisibleSong(_Actsong).VideoFileName));
|
||||
if (_Video == -1)
|
||||
_PreviewVideoStream = CBase.Video.Load(Path.Combine(song.Folder, song.VideoFileName));
|
||||
if (_PreviewVideoStream == -1)
|
||||
return;
|
||||
CBase.Video.Skip(_Video, startposition, CBase.Songs.GetVisibleSong(_Actsong).VideoGap);
|
||||
CBase.Video.Skip(_PreviewVideoStream, startposition, song.VideoGap);
|
||||
_VideoFadeTimer.Stop();
|
||||
_VideoFadeTimer.Reset();
|
||||
_VideoFadeTimer.Start();
|
||||
@@ -659,14 +574,10 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
CBase.Sound.FadeAndStop(stream, 0f, 0.75f);
|
||||
_Streams.Clear();
|
||||
|
||||
CBase.Video.Close(_Video);
|
||||
_Video = -1;
|
||||
CBase.Video.Close(_PreviewVideoStream);
|
||||
_PreviewVideoStream = -1;
|
||||
|
||||
CBase.Drawing.RemoveTexture(ref _Vidtex);
|
||||
|
||||
_Timer.Stop();
|
||||
_Timer.Reset();
|
||||
_SelectedInternal = _SelectedPending;
|
||||
}
|
||||
|
||||
#region ThemeEdit
|
||||
|
||||
@@ -61,6 +61,15 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
public CSongMenuTileBoard(int partyModeID)
|
||||
: base(partyModeID) {}
|
||||
|
||||
protected override int _PreviewId
|
||||
{
|
||||
set
|
||||
{
|
||||
base._PreviewId = value;
|
||||
_UpdatePreview();
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetActualSelection()
|
||||
{
|
||||
return _ActualSelection;
|
||||
@@ -70,15 +79,13 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
base.Init();
|
||||
|
||||
_Rect = _Theme.SongMenuTileBoard.TileRect;
|
||||
Rect = _Theme.SongMenuTileBoard.TileRect;
|
||||
|
||||
_NumW = _Theme.SongMenuTileBoard.NumW;
|
||||
_NumH = _Theme.SongMenuTileBoard.NumH;
|
||||
_SpaceW = _Theme.SongMenuTileBoard.SpaceW;
|
||||
_SpaceH = _Theme.SongMenuTileBoard.SpaceH;
|
||||
|
||||
_PendingTime = 100L;
|
||||
|
||||
_TileW = (int)((_Theme.SongMenuTileBoard.TileRect.W - _SpaceW * (_NumW - 1)) / _NumW);
|
||||
_TileH = (int)((_Theme.SongMenuTileBoard.TileRect.H - _SpaceH * (_NumH - 1)) / _NumH);
|
||||
|
||||
@@ -91,7 +98,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
for (int j = 0; j < _NumW; j++)
|
||||
{
|
||||
var rect = new SRectF(_Theme.SongMenuTileBoard.TileRect.X + j * (_TileW + _SpaceW),
|
||||
_Theme.SongMenuTileBoard.TileRect.Y + i * (_TileH + _SpaceH), _TileW, _TileH, _Rect.Z);
|
||||
_Theme.SongMenuTileBoard.TileRect.Y + i * (_TileH + _SpaceH), _TileW, _TileH, Rect.Z);
|
||||
var tile = new CStatic(_PartyModeID, _CoverTexture, Color, rect);
|
||||
_Tiles.Add(tile);
|
||||
}
|
||||
@@ -99,9 +106,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
_ScrollRect = new SRectF(0, 0, CBase.Settings.GetRenderW(), CBase.Settings.GetRenderH(), _Theme.SongMenuTileBoard.TileRect.Z);
|
||||
|
||||
_PreviewSelected = -1;
|
||||
_Offset = 0;
|
||||
|
||||
_CoverBig = _Theme.SongMenuTileBoard.StaticCoverBig;
|
||||
_TextBG = _Theme.SongMenuTileBoard.StaticTextBG;
|
||||
_DuetIcon = _Theme.SongMenuTileBoard.StaticDuetIcon;
|
||||
@@ -112,6 +116,9 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
_Artist = _Theme.SongMenuTileBoard.TextArtist;
|
||||
_Title = _Theme.SongMenuTileBoard.TextTitle;
|
||||
_SongLength = _Theme.SongMenuTileBoard.TextSongLength;
|
||||
|
||||
_PreviewId = -1;
|
||||
_Offset = 0;
|
||||
}
|
||||
|
||||
public override void Update(SScreenSongOptions songOptions)
|
||||
@@ -120,52 +127,98 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
if (songOptions.Selection.RandomOnly)
|
||||
{
|
||||
_Locked = _PreviewSelected;
|
||||
_ActualSelection = _PreviewSelected;
|
||||
_Locked = _PreviewId;
|
||||
_ActualSelection = _PreviewId;
|
||||
for (int i = 0; i < _Tiles.Count; i++)
|
||||
_Tiles[i].Selected = _Locked == i + _Offset;
|
||||
}
|
||||
}
|
||||
|
||||
private void _UpdatePreview()
|
||||
{
|
||||
//First hide everything so we just have to set what we actually want
|
||||
_CoverBig.Texture = _CoverBigTexture;
|
||||
_Artist.Text = String.Empty;
|
||||
_Title.Text = String.Empty;
|
||||
_SongLength.Text = String.Empty;
|
||||
_DuetIcon.Visible = false;
|
||||
_VideoIcon.Visible = false;
|
||||
_MedleyCalcIcon.Visible = false;
|
||||
_MedleyTagIcon.Visible = false;
|
||||
|
||||
//Check if nothing is selected (for preview)
|
||||
if (_PreviewId < 0)
|
||||
return;
|
||||
|
||||
if (CBase.Songs.IsInCategory())
|
||||
{
|
||||
CSong song = CBase.Songs.GetVisibleSong(_PreviewId);
|
||||
//Check if we have a valid song (song still visible, index >=0 etc is checked by framework)
|
||||
if (song == null)
|
||||
{
|
||||
//Display at least the category
|
||||
CCategory category = CBase.Songs.GetCategory(CBase.Songs.GetCurrentCategoryIndex());
|
||||
//Check if we have a valid category
|
||||
if (category == null)
|
||||
return;
|
||||
_CoverBig.Texture = category.CoverTextureBig;
|
||||
_Artist.Text = category.Name;
|
||||
return;
|
||||
}
|
||||
_CoverBig.Texture = song.CoverTextureBig;
|
||||
_Artist.Text = song.Artist;
|
||||
_Title.Text = song.Title;
|
||||
_DuetIcon.Visible = song.IsDuet;
|
||||
_VideoIcon.Visible = song.VideoFileName != "";
|
||||
_MedleyCalcIcon.Visible = song.Medley.Source == EDataSource.Calculated;
|
||||
_MedleyTagIcon.Visible = song.Medley.Source == EDataSource.Tag;
|
||||
|
||||
float time = CBase.Sound.GetLength(_PreviewSongStream);
|
||||
if (Math.Abs(song.Finish) > 0.001)
|
||||
time = song.Finish;
|
||||
|
||||
time -= song.Start;
|
||||
var min = (int)Math.Floor(time / 60f);
|
||||
var sec = (int)(time - min * 60f);
|
||||
_SongLength.Text = min.ToString("00") + ":" + sec.ToString("00");
|
||||
}
|
||||
else
|
||||
{
|
||||
CCategory category = CBase.Songs.GetCategory(_PreviewId);
|
||||
//Check if we have a valid category
|
||||
if (category == null)
|
||||
return;
|
||||
_CoverBig.Texture = category.CoverTextureBig;
|
||||
_Artist.Text = category.Name;
|
||||
|
||||
int num = category.GetNumSongsNotSung();
|
||||
String songOrSongs = (num == 1) ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
|
||||
_Title.Text = CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnShow()
|
||||
{
|
||||
if (CBase.Songs.GetTabs() == EOffOn.TR_CONFIG_OFF && CBase.Songs.GetNumCategories() > 0 && !CBase.Songs.IsInCategory())
|
||||
_EnterCategory(0);
|
||||
_ActualSelection = -1;
|
||||
_Locked = -1;
|
||||
_PreviewSelected = -1;
|
||||
_PreviewId = -1;
|
||||
_UpdateList(0, true);
|
||||
//AfterCategoryChange();
|
||||
SetSelectedSong(_ActSong);
|
||||
SetSelectedSong(_PreviewId);
|
||||
_AfterCategoryChange();
|
||||
|
||||
int actcat = _PreviewSelected;
|
||||
if ((CBase.Songs.GetNumCategories() > 0) && (actcat < 0))
|
||||
if (_PreviewId < 0)
|
||||
{
|
||||
_CoverBig.Texture = CBase.Songs.GetCategory(0).CoverTextureBig;
|
||||
_Artist.Text = CBase.Songs.GetCategory(0).Name;
|
||||
_Title.Text = String.Empty;
|
||||
_SongLength.Text = String.Empty;
|
||||
_PreviewSelected = 0;
|
||||
_PreviewId = 0;
|
||||
_Locked = 0;
|
||||
_DuetIcon.Visible = false;
|
||||
_VideoIcon.Visible = false;
|
||||
_MedleyCalcIcon.Visible = false;
|
||||
_MedleyTagIcon.Visible = false;
|
||||
}
|
||||
|
||||
if (CBase.Songs.GetNumSongsVisible() == 0 && CBase.Songs.GetSearchFilter() != "")
|
||||
{
|
||||
_CoverBig.Texture = _CoverBigTexture;
|
||||
_Artist.Text = String.Empty;
|
||||
_Title.Text = String.Empty;
|
||||
_SongLength.Text = String.Empty;
|
||||
_PreviewSelected = -1;
|
||||
_PreviewId = -1;
|
||||
_Locked = -1;
|
||||
_DuetIcon.Visible = false;
|
||||
_VideoIcon.Visible = false;
|
||||
_MedleyCalcIcon.Visible = false;
|
||||
_MedleyTagIcon.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,14 +238,13 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
if ((_Locked == -1 || !sel) &&
|
||||
(keyEvent.Key != Keys.Escape && keyEvent.Key != Keys.Back && keyEvent.Key != Keys.PageUp && keyEvent.Key != Keys.PageDown))
|
||||
{
|
||||
if (_PreviewSelected > -1)
|
||||
_Locked = _PreviewSelected;
|
||||
if (_PreviewId > -1)
|
||||
_Locked = _PreviewId;
|
||||
else
|
||||
{
|
||||
_Locked = 0;
|
||||
_ActualSelection = 0;
|
||||
_PreviewSelected = 0;
|
||||
_SetSelectedNow();
|
||||
_PreviewId = 0;
|
||||
_UpdateList(0, true);
|
||||
}
|
||||
}
|
||||
@@ -203,10 +255,10 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
case Keys.Enter:
|
||||
if (!CBase.Songs.IsInCategory())
|
||||
{
|
||||
_EnterCategory(_PreviewSelected);
|
||||
_EnterCategory(_PreviewId);
|
||||
keyEvent.Handled = true;
|
||||
}
|
||||
else if (_ActualSelection > -1 && _PreviewSelected >= 0)
|
||||
else if (_ActualSelection > -1 && _PreviewId >= 0)
|
||||
_Locked = _ActualSelection;
|
||||
break;
|
||||
|
||||
@@ -301,7 +353,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
if (!keyEvent.Handled)
|
||||
{
|
||||
_PreviewSelected = _Locked;
|
||||
_PreviewId = _Locked;
|
||||
_ActualSelection = _Locked;
|
||||
|
||||
for (int i = 0; i < _Tiles.Count; i++)
|
||||
@@ -318,7 +370,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
bool sel = false;
|
||||
int lastselection = _ActualSelection;
|
||||
|
||||
if (!songOptions.Selection.RandomOnly || !CBase.Songs.IsInCategory() && songOptions.Selection.CategoryChangeAllowed)
|
||||
if (!songOptions.Selection.RandomOnly || (!CBase.Songs.IsInCategory() && songOptions.Selection.CategoryChangeAllowed))
|
||||
{
|
||||
foreach (CStatic tile in _Tiles)
|
||||
{
|
||||
@@ -326,11 +378,11 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
if (mouseEvent.LB || !CBase.Songs.IsInCategory())
|
||||
{
|
||||
if (_PreviewSelected == i + _Offset)
|
||||
_Locked = _PreviewSelected;
|
||||
if (_PreviewId == i + _Offset)
|
||||
_Locked = _PreviewId;
|
||||
else
|
||||
{
|
||||
_PreviewSelected = i + _Offset;
|
||||
_PreviewId = i + _Offset;
|
||||
_Locked = -1;
|
||||
}
|
||||
}
|
||||
@@ -361,10 +413,10 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
}
|
||||
if (mouseEvent.RB && CBase.Songs.GetTabs() == EOffOn.TR_CONFIG_OFF && !songOptions.Selection.PartyMode)
|
||||
CBase.Graphics.FadeTo(EScreens.ScreenMain);
|
||||
else if (_PreviewSelected != -1 && mouseEvent.LB && CBase.Songs.GetCurrentCategoryIndex() != -1 && !songOptions.Selection.PartyMode)
|
||||
else if (_PreviewId != -1 && mouseEvent.LB && CBase.Songs.GetCurrentCategoryIndex() != -1 && !songOptions.Selection.PartyMode)
|
||||
{
|
||||
if (CHelper.IsInBounds(_CoverBig.Rect, mouseEvent) || CHelper.IsInBounds(_TextBG.Rect, mouseEvent))
|
||||
_Locked = _PreviewSelected;
|
||||
_Locked = _PreviewId;
|
||||
}
|
||||
else if (mouseEvent.LB && (!CBase.Songs.IsInCategory()))
|
||||
{
|
||||
@@ -372,7 +424,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
if (tile.Texture != _CoverTexture && CHelper.IsInBounds(tile.Rect, mouseEvent))
|
||||
{
|
||||
_EnterCategory(_PreviewSelected);
|
||||
_EnterCategory(_PreviewId);
|
||||
mouseEvent.Handled = true;
|
||||
return;
|
||||
}
|
||||
@@ -392,67 +444,14 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
tile.Draw(1.2f, tile.Rect.Z - 0.1f, EAspect.Crop);
|
||||
else
|
||||
{
|
||||
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
|
||||
if (tile.Texture != _CoverTexture)
|
||||
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
|
||||
tile.Draw(1f, tile.Rect.Z, EAspect.Crop);
|
||||
else
|
||||
tile.Draw(1f, tile.Rect.Z, EAspect.Stretch);
|
||||
}
|
||||
}
|
||||
|
||||
if (CBase.Songs.IsInCategory())
|
||||
{
|
||||
int actsong = _PreviewSelected;
|
||||
if ((CBase.Songs.GetNumSongsVisible() > actsong) && (actsong >= 0))
|
||||
{
|
||||
CSong song = CBase.Songs.GetVisibleSong(actsong);
|
||||
|
||||
_CoverBig.Texture = song.CoverTextureBig;
|
||||
_Artist.Text = song.Artist;
|
||||
_Title.Text = song.Title;
|
||||
_DuetIcon.Visible = song.IsDuet;
|
||||
_VideoIcon.Visible = song.VideoFileName != "";
|
||||
_MedleyCalcIcon.Visible = song.Medley.Source == EMedleySource.Calculated;
|
||||
_MedleyTagIcon.Visible = song.Medley.Source == EMedleySource.Tag;
|
||||
|
||||
float time = CBase.Sound.GetLength(_SongStream);
|
||||
if (Math.Abs(song.Finish) > 0.001)
|
||||
time = song.Finish;
|
||||
|
||||
time -= song.Start;
|
||||
var min = (int)Math.Floor(time / 60f);
|
||||
var sec = (int)(time - min * 60f);
|
||||
_SongLength.Text = min.ToString("00") + ":" + sec.ToString("00");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int actcat = _PreviewSelected;
|
||||
if ((CBase.Songs.GetNumCategories() > actcat) && (actcat >= 0))
|
||||
{
|
||||
_CoverBig.Texture = CBase.Songs.GetCategory(actcat).CoverTextureBig;
|
||||
_Artist.Text = CBase.Songs.GetCategory(actcat).Name;
|
||||
|
||||
int num = CBase.Songs.NumSongsInCategory(actcat);
|
||||
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
|
||||
if (num != 1)
|
||||
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
|
||||
_Title.Text = CBase.Language.Translate("TR_SCREENSONG_NUMSONGS").Replace("%v", num.ToString());
|
||||
else
|
||||
_Title.Text = CBase.Language.Translate("TR_SCREENSONG_NUMSONG").Replace("%v", num.ToString());
|
||||
|
||||
_SongLength.Text = String.Empty;
|
||||
_DuetIcon.Visible = false;
|
||||
_VideoIcon.Visible = false;
|
||||
_MedleyCalcIcon.Visible = false;
|
||||
_MedleyTagIcon.Visible = false;
|
||||
EAspect aspect = (tile.Texture != _CoverTexture) ? EAspect.Crop : EAspect.Stretch;
|
||||
tile.Draw(1f, tile.Rect.Z, aspect);
|
||||
}
|
||||
}
|
||||
|
||||
_TextBG.Draw();
|
||||
|
||||
if (_Vidtex != null && _Video != -1)
|
||||
if (_Vidtex != null && _PreviewVideoStream != -1)
|
||||
{
|
||||
if (_Vidtex.Color.A < 1)
|
||||
_CoverBig.Draw(1f, EAspect.Crop);
|
||||
@@ -508,14 +507,13 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
if (_Locked == -1 || !sel)
|
||||
{
|
||||
if (_PreviewSelected > -1)
|
||||
_Locked = _PreviewSelected;
|
||||
if (_PreviewId > -1)
|
||||
_Locked = _PreviewId;
|
||||
else
|
||||
{
|
||||
_Locked = 0;
|
||||
_ActualSelection = 0;
|
||||
_PreviewSelected = 0;
|
||||
_SetSelectedNow();
|
||||
_PreviewId = 0;
|
||||
_UpdateList(0, true);
|
||||
}
|
||||
}
|
||||
@@ -523,13 +521,12 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
foreach (CStatic tile in _Tiles)
|
||||
tile.Selected = false;
|
||||
|
||||
_PreviewSelected = itemNr;
|
||||
_SetSelectedNow();
|
||||
_PreviewId = itemNr;
|
||||
_Locked = itemNr;
|
||||
|
||||
_UpdateList(true);
|
||||
|
||||
_PreviewSelected = _Locked;
|
||||
_PreviewId = _Locked;
|
||||
_ActualSelection = _Locked;
|
||||
|
||||
if (_Locked - _Offset >= 0)
|
||||
@@ -556,7 +553,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
base._EnterCategory(cat);
|
||||
|
||||
_PreviewSelected = 0;
|
||||
_PreviewId = 0;
|
||||
_Locked = -1;
|
||||
_ActualSelection = 0;
|
||||
_AfterCategoryChange();
|
||||
@@ -567,7 +564,7 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
base._ShowCategories();
|
||||
|
||||
_PreviewSelected = 0;
|
||||
_PreviewId = 0;
|
||||
_Locked = -1;
|
||||
_ActualSelection = 0;
|
||||
_AfterCategoryChange();
|
||||
@@ -594,9 +591,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
|
||||
private void _AfterCategoryChange()
|
||||
{
|
||||
_SetSelectedNow();
|
||||
_SelectSong(_PreviewSelected);
|
||||
|
||||
foreach (CStatic tile in _Tiles)
|
||||
tile.Selected = false;
|
||||
|
||||
@@ -657,17 +651,17 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
_NumH = _Theme.SongMenuTileBoard.NumHsmall;
|
||||
_NumW = _Theme.SongMenuTileBoard.NumWsmall;
|
||||
_Rect = _Theme.SongMenuTileBoard.TileRectSmall;
|
||||
Rect = _Theme.SongMenuTileBoard.TileRectSmall;
|
||||
}
|
||||
else
|
||||
{
|
||||
_NumH = _Theme.SongMenuTileBoard.NumH;
|
||||
_NumW = _Theme.SongMenuTileBoard.NumW;
|
||||
_Rect = _Theme.SongMenuTileBoard.TileRect;
|
||||
Rect = _Theme.SongMenuTileBoard.TileRect;
|
||||
}
|
||||
|
||||
_TileW = (int)((_Rect.W - _SpaceW * (_NumW - 1)) / _NumW);
|
||||
_TileH = (int)((_Rect.H - _SpaceH * (_NumH - 1)) / _NumH);
|
||||
_TileW = (int)((Rect.W - _SpaceW * (_NumW - 1)) / _NumW);
|
||||
_TileH = (int)((Rect.H - _SpaceH * (_NumH - 1)) / _NumH);
|
||||
|
||||
_CoverTexture = CBase.Theme.GetSkinTexture(_Theme.CoverBackgroundName, _PartyModeID);
|
||||
_CoverBigTexture = CBase.Theme.GetSkinTexture(_Theme.CoverBigBackgroundName, _PartyModeID);
|
||||
@@ -677,13 +671,13 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
{
|
||||
for (int j = 0; j < _NumW; j++)
|
||||
{
|
||||
var rect = new SRectF(_Rect.X + j * (_TileW + _SpaceW), _Rect.Y + i * (_TileH + _SpaceH), _TileW, _TileH, _Rect.Z);
|
||||
var rect = new SRectF(Rect.X + j * (_TileW + _SpaceW), Rect.Y + i * (_TileH + _SpaceH), _TileW, _TileH, Rect.Z);
|
||||
var tile = new CStatic(_PartyModeID, _CoverTexture, Color, rect);
|
||||
_Tiles.Add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
_ScrollRect = new SRectF(0, 0, CBase.Settings.GetRenderW(), CBase.Settings.GetRenderH(), _Rect.Z);
|
||||
_ScrollRect = new SRectF(0, 0, CBase.Settings.GetRenderW(), CBase.Settings.GetRenderH(), Rect.Z);
|
||||
_UpdateList(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
bool IsSmallView();
|
||||
void SetSmallView(bool smallView);
|
||||
|
||||
SRectF GetRect();
|
||||
SRectF Rect { get; }
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,6 @@ namespace VocaluxeLib.Profile
|
||||
{
|
||||
public class CProfile
|
||||
{
|
||||
private static readonly XmlWriterSettings _Settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
Encoding = Encoding.UTF8,
|
||||
ConformanceLevel = ConformanceLevel.Document
|
||||
};
|
||||
|
||||
public int ID;
|
||||
|
||||
public string PlayerName;
|
||||
@@ -137,7 +130,7 @@ namespace VocaluxeLib.Profile
|
||||
XmlWriter writer;
|
||||
try
|
||||
{
|
||||
writer = XmlWriter.Create(Path.Combine(FilePath, FileName), _Settings);
|
||||
writer = XmlWriter.Create(Path.Combine(FilePath, FileName), CBase.Config.GetXMLSettings());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
/// <summary>
|
||||
@@ -38,12 +40,17 @@ namespace VocaluxeLib.Songs
|
||||
StartBeat = startBeat;
|
||||
Duration = duration;
|
||||
Tone = tone;
|
||||
if (Duration < 1)
|
||||
throw new Exception("Note to short. All notes should be at least 1 beat long!");
|
||||
}
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
public int StartBeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Last beat of this note. First valid beat for a note after that is at EndBeat+1
|
||||
/// </summary>
|
||||
public int EndBeat
|
||||
{
|
||||
get { return StartBeat + _Duration - 1; }
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using VocaluxeLib.Draw;
|
||||
using System.Linq;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
@@ -50,6 +51,11 @@ namespace VocaluxeLib.Songs
|
||||
}
|
||||
}
|
||||
|
||||
public int GetNumSongsNotSung()
|
||||
{
|
||||
return Songs.Count(sp => !sp.IsSung);
|
||||
}
|
||||
|
||||
public CCategory(string name, CTexture coverSmall, CTexture coverBig)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -74,7 +74,11 @@ namespace VocaluxeLib.Songs
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
//Find last note with StartBeat<=Beat
|
||||
/// <summary>
|
||||
/// Find last note with StartBeat<=Beat
|
||||
/// </summary>
|
||||
/// <param name="beat"></param>
|
||||
/// <returns>Note index of last note with StartBeat<=Beat or -1 if all notes start after beat</returns>
|
||||
public int FindPreviousNote(int beat)
|
||||
{
|
||||
//If no notes -> No previous note
|
||||
|
||||
+51
-10
@@ -21,24 +21,63 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
public class CNotes
|
||||
{
|
||||
private readonly List<CVoice> _Voices = new List<CVoice>();
|
||||
|
||||
public CVoice[] Voices
|
||||
public class CVoiceNames
|
||||
{
|
||||
get { return _Voices.ToArray(); }
|
||||
private readonly List<string> _Names = new List<string>();
|
||||
|
||||
public CVoiceNames() {}
|
||||
|
||||
public CVoiceNames(CVoiceNames names)
|
||||
{
|
||||
_Names.AddRange(names._Names);
|
||||
}
|
||||
|
||||
public string this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsSet(index))
|
||||
return _Names[index];
|
||||
return "Part " + (index + 1);
|
||||
}
|
||||
set
|
||||
{
|
||||
_Names.EnsureSize(index + 1, null);
|
||||
_Names[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSet(int index)
|
||||
{
|
||||
return _Names.Count > index && !string.IsNullOrEmpty(_Names[index]);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_Names.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<CVoice> _Voices = new List<CVoice>();
|
||||
public readonly CVoiceNames VoiceNames = new CVoiceNames();
|
||||
|
||||
public CNotes() {}
|
||||
|
||||
public int LinesCount
|
||||
{
|
||||
get { return _Voices.Count; }
|
||||
}
|
||||
|
||||
public CNotes(CNotes notes)
|
||||
{
|
||||
foreach (CVoice voice in notes._Voices)
|
||||
_Voices.Add(new CVoice(voice));
|
||||
VoiceNames = new CVoiceNames(notes.VoiceNames);
|
||||
}
|
||||
|
||||
public IEnumerable<CVoice> Voices
|
||||
{
|
||||
get { return _Voices; }
|
||||
}
|
||||
|
||||
public int VoiceCount
|
||||
{
|
||||
get { return _Voices.Count; }
|
||||
}
|
||||
|
||||
public CVoice GetVoice(int index)
|
||||
@@ -79,9 +118,11 @@ namespace VocaluxeLib.Songs
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
public void Reset(bool resetVoices = false)
|
||||
{
|
||||
_Voices.Clear();
|
||||
if (resetVoices)
|
||||
VoiceNames.Reset();
|
||||
}
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
|
||||
+126
-574
@@ -20,7 +20,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
@@ -45,12 +44,11 @@ namespace VocaluxeLib.Songs
|
||||
Artist = 2,
|
||||
MP3 = 4,
|
||||
BPM = 8,
|
||||
PreviewStart = 16,
|
||||
MedleyStartBeat = 32,
|
||||
MedleyEndBeat = 64
|
||||
MedleyStartBeat = 16,
|
||||
MedleyEndBeat = 32
|
||||
}
|
||||
|
||||
public enum EMedleySource
|
||||
public enum EDataSource
|
||||
{
|
||||
None = 0,
|
||||
Calculated,
|
||||
@@ -59,30 +57,43 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public struct SMedley
|
||||
{
|
||||
public EMedleySource Source;
|
||||
public EDataSource Source;
|
||||
public int StartBeat;
|
||||
public int EndBeat;
|
||||
public float FadeInTime;
|
||||
public float FadeOutTime;
|
||||
}
|
||||
|
||||
public class CSong
|
||||
public struct SShortEnd
|
||||
{
|
||||
public EDataSource Source;
|
||||
public int EndBeat;
|
||||
}
|
||||
|
||||
public struct SPreview
|
||||
{
|
||||
public EDataSource Source;
|
||||
public float StartTime;
|
||||
}
|
||||
|
||||
public partial class CSong
|
||||
{
|
||||
private CTexture _CoverTextureSmall;
|
||||
private CTexture _CoverTextureBig;
|
||||
|
||||
public SMedley Medley;
|
||||
|
||||
public bool CalculateMedley = true;
|
||||
public float PreviewStart;
|
||||
private bool _CalculateMedley = true;
|
||||
public SPreview Preview;
|
||||
|
||||
public int ShortEnd;
|
||||
public SShortEnd ShortEnd;
|
||||
|
||||
public Encoding Encoding = Encoding.Default;
|
||||
public bool ManualEncoding;
|
||||
public string Folder = String.Empty;
|
||||
public string FolderName = String.Empty;
|
||||
public string FileName = String.Empty;
|
||||
public EOffOn Relative = EOffOn.TR_CONFIG_OFF;
|
||||
public bool Relative;
|
||||
|
||||
public string MP3FileName = String.Empty;
|
||||
public string CoverFileName = String.Empty;
|
||||
@@ -117,17 +128,31 @@ namespace VocaluxeLib.Songs
|
||||
public string TitleSorting = String.Empty;
|
||||
public string ArtistSorting = String.Empty;
|
||||
|
||||
public string Creator = "";
|
||||
public string Version = "";
|
||||
public string Source = "";
|
||||
public readonly List<String> UnknownTags = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Start of the song in s (s in txt)
|
||||
/// </summary>
|
||||
public float Start;
|
||||
/// <summary>
|
||||
/// End of the song in s (ms in txt)
|
||||
/// </summary>
|
||||
public float Finish;
|
||||
|
||||
public float BPM = 1f;
|
||||
/// <summary>
|
||||
/// Gap of the mp3 in s (ms in txt)
|
||||
/// </summary>
|
||||
public float Gap;
|
||||
/// <summary>
|
||||
/// Gap of the video in s (s in txt)
|
||||
/// </summary>
|
||||
public float VideoGap;
|
||||
|
||||
public string DuetPart1 = String.Empty;
|
||||
public string DuetPart2 = String.Empty;
|
||||
|
||||
private readonly List<string> _Comment = new List<string>();
|
||||
private string _Comment = "";
|
||||
|
||||
// Sorting
|
||||
public int ID;
|
||||
@@ -136,14 +161,15 @@ namespace VocaluxeLib.Songs
|
||||
private readonly bool _Selected;
|
||||
public bool IsDuet
|
||||
{
|
||||
get { return Notes.Voices.Length > 1; }
|
||||
get { return Notes.VoiceCount > 1; }
|
||||
}
|
||||
|
||||
public readonly List<string> Edition = new List<string>();
|
||||
public readonly List<string> Genre = new List<string>();
|
||||
public readonly List<string> Editions = new List<string>();
|
||||
public readonly List<string> Genres = new List<string>();
|
||||
public string Album = "";
|
||||
public string Year = "";
|
||||
|
||||
public readonly List<string> Language = new List<string>();
|
||||
public readonly List<string> Languages = new List<string>();
|
||||
|
||||
public int DataBaseSongID = -1;
|
||||
public string DateAdded = "";
|
||||
@@ -152,50 +178,47 @@ namespace VocaluxeLib.Songs
|
||||
// Notes
|
||||
public readonly CNotes Notes = new CNotes();
|
||||
|
||||
public EGameMode[] AvailableGameModes
|
||||
public IList<EGameMode> AvailableGameModes
|
||||
{
|
||||
get
|
||||
{
|
||||
var gms = new List<EGameMode> {IsDuet ? EGameMode.TR_GAMEMODE_DUET : EGameMode.TR_GAMEMODE_NORMAL};
|
||||
if (Medley.Source != EMedleySource.None)
|
||||
if (Medley.Source != EDataSource.None)
|
||||
gms.Add(EGameMode.TR_GAMEMODE_MEDLEY);
|
||||
gms.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
if (ShortEnd.Source != EDataSource.None)
|
||||
gms.Add(EGameMode.TR_GAMEMODE_SHORTSONG);
|
||||
|
||||
return gms.ToArray();
|
||||
return gms;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the requested game mode is available
|
||||
/// </summary>
|
||||
/// <param name="gameMode"></param>
|
||||
/// <returns>true if the requested game mode is available</returns>
|
||||
public bool IsGameModeAvailable(EGameMode gameMode)
|
||||
{
|
||||
return AvailableGameModes.Any(gm => gm == gameMode);
|
||||
}
|
||||
|
||||
//No point creating a song without a text file --> Use factory method LoadSong
|
||||
private CSong() {}
|
||||
|
||||
public static CSong LoadSong(string filePath)
|
||||
{
|
||||
var song = new CSong();
|
||||
return song.ReadHeader(filePath) ? song : null;
|
||||
}
|
||||
|
||||
public CSong(CSong song)
|
||||
{
|
||||
_CoverTextureSmall = song._CoverTextureSmall;
|
||||
_CoverTextureBig = song._CoverTextureBig;
|
||||
|
||||
Medley = new SMedley
|
||||
{
|
||||
Source = song.Medley.Source,
|
||||
StartBeat = song.Medley.StartBeat,
|
||||
EndBeat = song.Medley.EndBeat,
|
||||
FadeInTime = song.Medley.FadeInTime,
|
||||
FadeOutTime = song.Medley.FadeOutTime
|
||||
};
|
||||
Medley = song.Medley;
|
||||
|
||||
CalculateMedley = song.CalculateMedley;
|
||||
PreviewStart = song.PreviewStart;
|
||||
_CalculateMedley = song._CalculateMedley;
|
||||
Preview = song.Preview;
|
||||
|
||||
ShortEnd = song.ShortEnd;
|
||||
DuetPart1 = song.DuetPart1;
|
||||
DuetPart2 = song.DuetPart2;
|
||||
|
||||
Encoding = song.Encoding;
|
||||
ManualEncoding = song.ManualEncoding;
|
||||
Folder = song.Folder;
|
||||
FolderName = song.FolderName;
|
||||
FileName = song.FileName;
|
||||
@@ -211,6 +234,13 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
Artist = song.Artist;
|
||||
Title = song.Title;
|
||||
ArtistSorting = song.ArtistSorting;
|
||||
TitleSorting = song.TitleSorting;
|
||||
|
||||
Creator = song.Creator;
|
||||
Version = song.Version;
|
||||
Source = song.Source;
|
||||
UnknownTags = new List<string>(song.UnknownTags);
|
||||
|
||||
Start = song.Start;
|
||||
Finish = song.Finish;
|
||||
@@ -219,28 +249,19 @@ namespace VocaluxeLib.Songs
|
||||
Gap = song.Gap;
|
||||
VideoGap = song.VideoGap;
|
||||
|
||||
_Comment = new List<string>();
|
||||
foreach (string value in song._Comment)
|
||||
_Comment.Add(value);
|
||||
_Comment = song._Comment;
|
||||
|
||||
ID = song.ID;
|
||||
_Visible = song._Visible;
|
||||
_CatIndex = song._CatIndex;
|
||||
_Selected = song._Selected;
|
||||
|
||||
Edition = new List<string>();
|
||||
foreach (string value in song.Edition)
|
||||
Edition.Add(value);
|
||||
|
||||
Genre = new List<string>();
|
||||
foreach (string value in song.Genre)
|
||||
Genre.Add(value);
|
||||
|
||||
Editions = new List<string>(song.Editions);
|
||||
Genres = new List<string>(song.Genres);
|
||||
Album = song.Album;
|
||||
Year = song.Year;
|
||||
|
||||
Language = new List<string>();
|
||||
foreach (string value in song.Language)
|
||||
Language.Add(value);
|
||||
Languages = new List<string>(song.Languages);
|
||||
|
||||
DataBaseSongID = song.DataBaseSongID;
|
||||
DateAdded = song.DateAdded;
|
||||
@@ -249,6 +270,25 @@ namespace VocaluxeLib.Songs
|
||||
Notes = new CNotes(song.Notes);
|
||||
}
|
||||
|
||||
public static CSong LoadSong(string filePath)
|
||||
{
|
||||
var song = new CSong();
|
||||
var loader = new CSongLoader(song);
|
||||
return loader.InitPaths(filePath) && loader.ReadHeader() ? song : null;
|
||||
}
|
||||
|
||||
public bool LoadNotes()
|
||||
{
|
||||
var loader = new CSongLoader(this);
|
||||
return loader.ReadNotes();
|
||||
}
|
||||
|
||||
public bool Save(string filePath)
|
||||
{
|
||||
var writer = new CSongWriter(this);
|
||||
return writer.SaveFile(filePath);
|
||||
}
|
||||
|
||||
public string GetMP3()
|
||||
{
|
||||
return Path.Combine(Folder, MP3FileName);
|
||||
@@ -259,494 +299,6 @@ namespace VocaluxeLib.Songs
|
||||
return Path.Combine(Folder, VideoFileName);
|
||||
}
|
||||
|
||||
public bool ReadHeader(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
Folder = Path.GetDirectoryName(filePath);
|
||||
if (Folder == null)
|
||||
return false;
|
||||
|
||||
foreach (string folder in CBase.Config.GetSongFolder())
|
||||
{
|
||||
if (!Folder.Contains(folder))
|
||||
continue;
|
||||
if (Folder.Length == folder.Length)
|
||||
FolderName = "Songs";
|
||||
else
|
||||
{
|
||||
FolderName = Folder.Substring(folder.Length + 1, Folder.Length - folder.Length - 1);
|
||||
|
||||
int pos = FolderName.IndexOf("\\", StringComparison.Ordinal);
|
||||
if (pos >= 0)
|
||||
FolderName = FolderName.Substring(0, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
FileName = Path.GetFileName(filePath);
|
||||
|
||||
var headerFlags = new EHeaderFlags();
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, Encoding.Default, true);
|
||||
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].ToString().Equals("#"))
|
||||
break;
|
||||
|
||||
int pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos <= 0)
|
||||
continue;
|
||||
string identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
string value = line.Substring(pos + 1, line.Length - pos - 1).Trim();
|
||||
|
||||
if (value != "")
|
||||
{
|
||||
switch (identifier)
|
||||
{
|
||||
case "ENCODING":
|
||||
Encoding = CEncoding.GetEncoding(value);
|
||||
sr.Dispose();
|
||||
sr = null;
|
||||
sr = new StreamReader(filePath, Encoding);
|
||||
|
||||
//Scip everything till encoding
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
line = sr.ReadLine();
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].ToString().Equals("#"))
|
||||
break;
|
||||
|
||||
pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
if (identifier == "ENCODING")
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "TITLE":
|
||||
if (value != "")
|
||||
{
|
||||
Title = value;
|
||||
headerFlags |= EHeaderFlags.Title;
|
||||
}
|
||||
break;
|
||||
case "ARTIST":
|
||||
if (value != "")
|
||||
{
|
||||
Artist = value;
|
||||
headerFlags |= EHeaderFlags.Artist;
|
||||
}
|
||||
break;
|
||||
case "TITLE-ON-SORTING":
|
||||
if (value != "")
|
||||
TitleSorting = value;
|
||||
break;
|
||||
case "ARTIST-ON-SORTING":
|
||||
if (value != "")
|
||||
ArtistSorting = value;
|
||||
break;
|
||||
case "DUETSINGERP1":
|
||||
case "P1":
|
||||
if (value != "")
|
||||
DuetPart1 = value;
|
||||
break;
|
||||
case "DUETSINGERP2":
|
||||
case "P2":
|
||||
if (value != "")
|
||||
DuetPart2 = value;
|
||||
break;
|
||||
case "MP3":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
{
|
||||
MP3FileName = value;
|
||||
headerFlags |= EHeaderFlags.MP3;
|
||||
}
|
||||
else
|
||||
{
|
||||
CBase.Log.LogError("Can't find audio file: " + Path.Combine(Folder, value));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "BPM":
|
||||
if (CHelper.TryParse(value, out BPM))
|
||||
{
|
||||
BPM *= 4;
|
||||
headerFlags |= EHeaderFlags.BPM;
|
||||
}
|
||||
break;
|
||||
case "EDITION":
|
||||
if (value.Length > 1)
|
||||
Edition.Add(value);
|
||||
break;
|
||||
case "GENRE":
|
||||
if (value.Length > 1)
|
||||
Genre.Add(value);
|
||||
break;
|
||||
case "YEAR":
|
||||
int num;
|
||||
if (value.Length == 4 && int.TryParse(value, out num) && num != 0)
|
||||
Year = value;
|
||||
break;
|
||||
case "LANGUAGE":
|
||||
if (value.Length > 1)
|
||||
Language.Add(value);
|
||||
break;
|
||||
case "COMMENT":
|
||||
if (value.Length > 1)
|
||||
_Comment.Add(value);
|
||||
break;
|
||||
case "GAP":
|
||||
if (CHelper.TryParse(value, out Gap))
|
||||
Gap /= 1000f;
|
||||
break;
|
||||
case "COVER":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
CoverFileName = value;
|
||||
break;
|
||||
case "BACKGROUND":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
BackgroundFileName = value;
|
||||
break;
|
||||
case "VIDEO":
|
||||
if (File.Exists(Path.Combine(Folder, value)))
|
||||
VideoFileName = value;
|
||||
else
|
||||
CBase.Log.LogError("Can't find video file: " + Path.Combine(Folder, value));
|
||||
break;
|
||||
case "VIDEOGAP":
|
||||
CHelper.TryParse(value, out VideoGap);
|
||||
break;
|
||||
case "VIDEOASPECT":
|
||||
CHelper.TryParse(value, out VideoAspect, true);
|
||||
break;
|
||||
case "START":
|
||||
CHelper.TryParse(value, out Start);
|
||||
break;
|
||||
case "END":
|
||||
if (CHelper.TryParse(value, out Finish))
|
||||
Finish /= 1000f;
|
||||
break;
|
||||
case "PREVIEWSTART":
|
||||
if (CHelper.TryParse(value, out PreviewStart))
|
||||
{
|
||||
if (PreviewStart < 0f)
|
||||
PreviewStart = 0f;
|
||||
else
|
||||
headerFlags |= EHeaderFlags.PreviewStart;
|
||||
}
|
||||
break;
|
||||
case "MEDLEYSTARTBEAT":
|
||||
if (int.TryParse(value, out Medley.StartBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyStartBeat;
|
||||
break;
|
||||
case "MEDLEYENDBEAT":
|
||||
if (int.TryParse(value, out Medley.EndBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyEndBeat;
|
||||
break;
|
||||
case "CALCMEDLEY":
|
||||
if (value.ToUpper() == "OFF")
|
||||
CalculateMedley = false;
|
||||
break;
|
||||
case "RELATIVE":
|
||||
if (value.ToUpper() == "YES" && value.ToUpper() != "NO")
|
||||
Relative = EOffOn.TR_CONFIG_ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} //end of while
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
//No other data then header
|
||||
CBase.Log.LogError("Lyrics/Notes missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Title) == 0)
|
||||
{
|
||||
CBase.Log.LogError("Title tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Artist) == 0)
|
||||
{
|
||||
CBase.Log.LogError("Artist tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MP3) == 0)
|
||||
{
|
||||
CBase.Log.LogError("MP3 tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.BPM) == 0)
|
||||
{
|
||||
CBase.Log.LogError("BPM tag missing: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
#region check medley tags
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
if (Medley.StartBeat > Medley.EndBeat)
|
||||
{
|
||||
CBase.Log.LogError("MedleyStartBeat is bigger than MedleyEndBeat in file: " + filePath);
|
||||
headerFlags = headerFlags - EHeaderFlags.MedleyStartBeat - EHeaderFlags.MedleyEndBeat;
|
||||
}
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.PreviewStart) == 0 || Math.Abs(PreviewStart) < float.Epsilon)
|
||||
{
|
||||
//PreviewStart is not set or <=0
|
||||
PreviewStart = (headerFlags & EHeaderFlags.MedleyStartBeat) != 0 ? CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) : 0f;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
Medley.Source = EMedleySource.Tag;
|
||||
Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
#endregion check medley tags
|
||||
|
||||
Encoding = sr.CurrentEncoding;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
CBase.Log.LogError("Error reading txt header in file \"" + filePath + "\": " + e.Message);
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
_CheckFiles();
|
||||
|
||||
CBase.DataBase.GetDataBaseSongInfos(Artist, Title, out NumPlayed, out DateAdded, out DataBaseSongID);
|
||||
|
||||
//Before saving this tags to .txt: Check, if ArtistSorting and Artist are equal, then don't save this tag.
|
||||
if (ArtistSorting == "")
|
||||
ArtistSorting = Artist;
|
||||
|
||||
if (TitleSorting == "")
|
||||
TitleSorting = Title;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ReadNotes()
|
||||
{
|
||||
return _ReadNotes(Path.Combine(Folder, FileName));
|
||||
}
|
||||
|
||||
private bool _ReadNotes(string filePath, bool forceReload = false)
|
||||
{
|
||||
//Skip loading if already done and no reload is forced
|
||||
if (NotesLoaded && !forceReload)
|
||||
return true;
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. The file does not exist: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
char tempC = char.MinValue;
|
||||
int currentPos = 0;
|
||||
bool isNewSentence = false;
|
||||
|
||||
int player = 0;
|
||||
int fileLineNo = 0;
|
||||
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, Encoding, true);
|
||||
|
||||
Notes.Reset();
|
||||
|
||||
//Search for Note Beginning
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
sr.ReadLine();
|
||||
fileLineNo++;
|
||||
|
||||
tempC = (char)sr.Peek();
|
||||
if ((tempC == '#') || (tempC == '\r') || (tempC == '\n'))
|
||||
continue;
|
||||
if ((tempC == ':') || (tempC == 'F') || (tempC == '*') || (tempC == 'P'))
|
||||
{
|
||||
tempC = (char)sr.Read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". No lyrics/notes found: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int param2;
|
||||
int param1;
|
||||
switch (tempC)
|
||||
{
|
||||
case 'P':
|
||||
char chr;
|
||||
while ((chr = (char)sr.Read()) == ' ') {}
|
||||
|
||||
int.TryParse(chr.ToString(), out param1);
|
||||
if (param1 == 1)
|
||||
player = 0;
|
||||
else if (param1 == 2)
|
||||
player = 1;
|
||||
else if (param1 == 3)
|
||||
player = 2;
|
||||
else
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Wrong or missing number after \"P\": " + filePath);
|
||||
return false;
|
||||
}
|
||||
sr.ReadLine();
|
||||
break;
|
||||
case ':':
|
||||
case '*':
|
||||
case 'F':
|
||||
sr.Read();
|
||||
param1 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
param2 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
int param3 = CHelper.TryReadInt(sr);
|
||||
|
||||
sr.Read();
|
||||
string paramS = sr.ReadLine();
|
||||
|
||||
ENoteType noteType;
|
||||
|
||||
if (tempC.CompareTo('*') == 0)
|
||||
noteType = ENoteType.Golden;
|
||||
else if (tempC.CompareTo('F') == 0)
|
||||
noteType = ENoteType.Freestyle;
|
||||
else
|
||||
noteType = ENoteType.Normal;
|
||||
|
||||
if (Relative == EOffOn.TR_CONFIG_ON)
|
||||
param1 += currentPos;
|
||||
|
||||
if (player != 2)
|
||||
// one singer
|
||||
_ParseNote(player, noteType, param1, param2, param3, paramS);
|
||||
else
|
||||
{
|
||||
// both singer
|
||||
_ParseNote(0, noteType, param1, param2, param3, paramS);
|
||||
_ParseNote(1, noteType, param1, param2, param3, paramS);
|
||||
}
|
||||
isNewSentence = false;
|
||||
break;
|
||||
case '-':
|
||||
if (isNewSentence)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Double sentence break: " + filePath);
|
||||
return false;
|
||||
}
|
||||
sr.Read();
|
||||
param1 = CHelper.TryReadInt(sr);
|
||||
|
||||
if (Relative == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
param1 += currentPos;
|
||||
sr.Read();
|
||||
param2 = CHelper.TryReadInt(sr);
|
||||
currentPos += param2;
|
||||
}
|
||||
|
||||
if (player != 2)
|
||||
// one singer
|
||||
_NewSentence(player, param1);
|
||||
else
|
||||
{
|
||||
// both singer
|
||||
_NewSentence(0, param1);
|
||||
_NewSentence(1, param1);
|
||||
}
|
||||
|
||||
isNewSentence = true;
|
||||
sr.ReadLine();
|
||||
break;
|
||||
default:
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". Unexpected or missing character (" + tempC + "): " + filePath);
|
||||
return false;
|
||||
}
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = sr.Read();
|
||||
} while (!sr.EndOfStream && (c == 19 || c == 16 || c == 13 || c == 10));
|
||||
tempC = (char)c;
|
||||
fileLineNo++;
|
||||
} while (!sr.EndOfStream && (tempC != 'E'));
|
||||
|
||||
foreach (CVoice voice in Notes.Voices)
|
||||
voice.UpdateTimings();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. Line No.: " + fileLineNo + ". An unhandled exception occured (" + e.Message + "): " + filePath);
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
try
|
||||
{
|
||||
_FindRefrain();
|
||||
_FindShortEnd();
|
||||
NotesLoaded = true;
|
||||
if (IsDuet)
|
||||
_CheckDuet();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Error loading song. An unhandled exception occured (" + e.Message + "): " + filePath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool _ParseNote(int player, ENoteType noteType, int start, int length, int tone, string text)
|
||||
{
|
||||
var note = new CSongNote(start, length, tone, text, noteType);
|
||||
CVoice voice = Notes.GetVoice(player);
|
||||
return voice.AddNote(note);
|
||||
}
|
||||
|
||||
private void _NewSentence(int player, int start)
|
||||
{
|
||||
CVoice voice = Notes.GetVoice(player);
|
||||
var line = new CSongLine {StartBeat = start};
|
||||
voice.AddLine(line);
|
||||
}
|
||||
|
||||
public void LoadSmallCover()
|
||||
{
|
||||
if (_CoverTextureSmall != null)
|
||||
@@ -765,11 +317,13 @@ namespace VocaluxeLib.Songs
|
||||
if (CoverFileName == "")
|
||||
{
|
||||
List<string> files = CHelper.ListFiles(Folder, "*.jpg");
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.png"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
|
||||
foreach (String file in files)
|
||||
{
|
||||
if (Regex.IsMatch(file, @".[CO].", RegexOptions.IgnoreCase) &&
|
||||
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase)))
|
||||
if (file.ContainsIgnoreCase("[CO]") &&
|
||||
(file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
|
||||
CoverFileName = file;
|
||||
}
|
||||
}
|
||||
@@ -777,11 +331,13 @@ namespace VocaluxeLib.Songs
|
||||
if (BackgroundFileName == "")
|
||||
{
|
||||
List<string> files = CHelper.ListFiles(Folder, "*.jpg");
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.jpeg"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.png"));
|
||||
files.AddRange(CHelper.ListFiles(Folder, "*.gif"));
|
||||
foreach (String file in files)
|
||||
{
|
||||
if (Regex.IsMatch(file, @".[BG].", RegexOptions.IgnoreCase) &&
|
||||
(Regex.IsMatch(file, @"" + Regex.Escape(Title), RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"" + Regex.Escape(Artist), RegexOptions.IgnoreCase)))
|
||||
if (file.ContainsIgnoreCase("[BG]") &&
|
||||
(file.ContainsIgnoreCase(Title) || file.ContainsIgnoreCase(Artist)))
|
||||
BackgroundFileName = file;
|
||||
}
|
||||
}
|
||||
@@ -789,15 +345,10 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
private void _CheckDuet()
|
||||
{
|
||||
if (DuetPart1 == "")
|
||||
for (int i = 0; i < Notes.VoiceCount; i++)
|
||||
{
|
||||
DuetPart1 = "Part 1";
|
||||
CBase.Log.LogError("Warning: Can't find #P1-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
}
|
||||
if (DuetPart2 == "")
|
||||
{
|
||||
DuetPart2 = "Part 2";
|
||||
CBase.Log.LogError("Warning: Can't find #P2-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
if (!Notes.VoiceNames.IsSet(i))
|
||||
CBase.Log.LogError("Warning: Can't find #P" + (i + 1) + "-tag for duets in \"" + Artist + " - " + Title + "\".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,14 +404,11 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (IsDuet)
|
||||
{
|
||||
Medley.Source = EMedleySource.None;
|
||||
Medley.Source = EDataSource.None;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Medley.Source == EMedleySource.Tag)
|
||||
return;
|
||||
|
||||
if (!CalculateMedley)
|
||||
if (!_CalculateMedley)
|
||||
return;
|
||||
|
||||
List<SSeries> series = _GetSeries();
|
||||
@@ -883,41 +431,44 @@ namespace VocaluxeLib.Songs
|
||||
Medley.StartBeat = voice.Lines[series[longest].Start].FirstNoteBeat;
|
||||
Medley.EndBeat = voice.Lines[series[longest].End].LastNoteBeat;
|
||||
|
||||
bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) + CBase.Settings.GetMedleyMinDuration() >
|
||||
CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM);
|
||||
bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) < CBase.Settings.GetMedleyMinDuration();
|
||||
|
||||
// set end if duration > MedleyMinDuration
|
||||
// set end if duration < MedleyMinDuration
|
||||
|
||||
if (!foundEnd)
|
||||
{
|
||||
for (int i = series[longest].Start + 1; i < voice.NumLines - 1; i++)
|
||||
for (int i = series[longest].End + 1; i < voice.NumLines - 1; i++)
|
||||
{
|
||||
if (CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) + CBase.Settings.GetMedleyMinDuration() >
|
||||
CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM))
|
||||
if (CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) <
|
||||
CBase.Settings.GetMedleyMinDuration())
|
||||
{
|
||||
foundEnd = true;
|
||||
Medley.EndBeat = voice.Lines[i].LastNoteBeat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundEnd)
|
||||
{
|
||||
Medley.Source = EMedleySource.Calculated;
|
||||
Medley.Source = EDataSource.Calculated;
|
||||
Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(PreviewStart) < 0.001)
|
||||
if (Preview.Source == EDataSource.None)
|
||||
{
|
||||
if (Medley.Source == EMedleySource.Calculated)
|
||||
PreviewStart = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM);
|
||||
if (Medley.Source != EDataSource.None)
|
||||
Preview.StartTime = CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM);
|
||||
}
|
||||
}
|
||||
|
||||
private void _FindShortEnd()
|
||||
{
|
||||
if (ShortEnd.Source != EDataSource.None)
|
||||
return;
|
||||
|
||||
List<SSeries> series = _GetSeries();
|
||||
if (series == null)
|
||||
return;
|
||||
@@ -934,10 +485,10 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (stop < (voice.Lines[series[i].Start].FirstNoteBeat + ((voice.Lines[series[i].End].LastNoteBeat - voice.Lines[series[i].Start].FirstNoteBeat) / 2)))
|
||||
{
|
||||
ShortEnd = voice.Lines[series[i].Start - 1].LastNote.EndBeat;
|
||||
ShortEnd.EndBeat = voice.Lines[series[i].Start - 1].LastNote.EndBeat;
|
||||
return;
|
||||
}
|
||||
ShortEnd = voice.Lines[series[i].End].LastNote.EndBeat;
|
||||
ShortEnd.EndBeat = voice.Lines[series[i].End].LastNote.EndBeat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -947,12 +498,13 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
if (line.FirstNoteBeat < stop && line.LastNoteBeat > stop)
|
||||
{
|
||||
ShortEnd = line.LastNoteBeat;
|
||||
ShortEnd.EndBeat = line.LastNoteBeat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ShortEnd = stop;
|
||||
ShortEnd.EndBeat = stop;
|
||||
ShortEnd.Source = EDataSource.Calculated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
public class CSongLine : CLineBase<CSongNote>
|
||||
{
|
||||
private int _StartBeat = int.MinValue;
|
||||
private int _StartBeat = int.MaxValue;
|
||||
private int _EndBeat = int.MinValue;
|
||||
|
||||
#region Constructors
|
||||
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public int StartBeat
|
||||
{
|
||||
get { return _StartBeat; }
|
||||
get { return Math.Min(_StartBeat, FirstNoteBeat); }
|
||||
set
|
||||
{
|
||||
if (value <= FirstNoteBeat)
|
||||
@@ -56,7 +56,7 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public int EndBeat
|
||||
{
|
||||
get { return _EndBeat; }
|
||||
get { return Math.Min(_EndBeat, LastNoteBeat); }
|
||||
set
|
||||
{
|
||||
if (value >= LastNoteBeat)
|
||||
@@ -77,12 +77,19 @@ namespace VocaluxeLib.Songs
|
||||
_Notes.Add(note);
|
||||
else
|
||||
{
|
||||
//Insert AFTER this note
|
||||
int insPos = FindPreviousNote(note.StartBeat);
|
||||
//Check for overlapping notes
|
||||
if (insPos >= 0 && _Notes[insPos].EndBeat > note.StartBeat)
|
||||
return false;
|
||||
if (insPos < _Notes.Count - 1 && _Notes[insPos + 1].StartBeat > note.EndBeat)
|
||||
return false;
|
||||
if (insPos >= 0) //Check note before
|
||||
{
|
||||
if (_Notes[insPos].EndBeat >= note.StartBeat)
|
||||
return false;
|
||||
}
|
||||
if (insPos < _Notes.Count - 1) //Check note after
|
||||
{
|
||||
if (_Notes[insPos + 1].StartBeat <= note.EndBeat)
|
||||
return false;
|
||||
}
|
||||
_Notes.Insert(insPos + 1, note);
|
||||
}
|
||||
return true;
|
||||
@@ -90,11 +97,8 @@ namespace VocaluxeLib.Songs
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
{
|
||||
foreach (CSongNote note in _Notes)
|
||||
{
|
||||
if (note.StartBeat < startBeat || note.EndBeat > endBeat)
|
||||
note.NoteType = ENoteType.Freestyle;
|
||||
}
|
||||
foreach (CSongNote note in _Notes.Where(note => note.StartBeat < startBeat || note.EndBeat > endBeat))
|
||||
note.Type = ENoteType.Freestyle;
|
||||
|
||||
VisibleInTimeLine = FirstNoteBeat >= startBeat && LastNoteBeat <= endBeat;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,740 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
/// <summary>
|
||||
/// Part of CSong that is required for note loading
|
||||
/// </summary>
|
||||
public partial class CSong
|
||||
{
|
||||
/// <summary>
|
||||
/// Factor the bpm given in the txt is multiplied with
|
||||
/// </summary>
|
||||
private const int _BPMFactor = 4;
|
||||
|
||||
private class CSongLoader
|
||||
{
|
||||
private readonly CSong _Song;
|
||||
private int _LineNr;
|
||||
|
||||
public CSongLoader(CSong song)
|
||||
{
|
||||
_Song = song;
|
||||
}
|
||||
|
||||
public bool InitPaths(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
_Song.Folder = Path.GetDirectoryName(filePath);
|
||||
if (_Song.Folder == null)
|
||||
return false;
|
||||
|
||||
foreach (string folder in CBase.Config.GetSongFolders().Where(folder => _Song.Folder.StartsWith(folder)))
|
||||
{
|
||||
if (_Song.Folder.Length == folder.Length)
|
||||
_Song.FolderName = "Songs";
|
||||
else
|
||||
{
|
||||
_Song.FolderName = _Song.Folder.Substring(folder.Length + 1);
|
||||
|
||||
int pos = _Song.FolderName.IndexOf("\\", StringComparison.Ordinal);
|
||||
if (pos >= 0)
|
||||
_Song.FolderName = _Song.FolderName.Substring(0, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_Song.FileName = Path.GetFileName(filePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a given message with file name and line#
|
||||
/// </summary>
|
||||
/// <param name="msg">Message</param>
|
||||
/// <param name="error">True prepends "Error: "; False prepends "Warning: "</param>
|
||||
/// <param name="withLineNr">Adds line#</param>
|
||||
private void _LogMsg(string msg, bool error, bool withLineNr)
|
||||
{
|
||||
msg = (error ? "Error: " : "Warning: ") + msg;
|
||||
if (withLineNr)
|
||||
msg += " in line #" + _LineNr;
|
||||
CBase.Log.LogError(msg + " (" + Path.Combine(_Song.Folder, _Song.FileName) + ")");
|
||||
}
|
||||
|
||||
private void _LogError(string msg, bool withLineNr = true)
|
||||
{
|
||||
_LogMsg(msg, true, withLineNr);
|
||||
}
|
||||
|
||||
private void _LogWarning(string msg, bool withLineNr = true)
|
||||
{
|
||||
_LogMsg(msg, false, withLineNr);
|
||||
}
|
||||
|
||||
public bool ReadHeader(bool useSetEncoding = false)
|
||||
{
|
||||
string filePath = Path.Combine(_Song.Folder, _Song.FileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
_Song.Languages.Clear();
|
||||
_Song.Genres.Clear();
|
||||
_Song.UnknownTags.Clear();
|
||||
_Song._Comment = "";
|
||||
_Song.ManualEncoding = false;
|
||||
_Song.Medley.Source = EDataSource.None;
|
||||
_Song._CalculateMedley = true;
|
||||
_Song.Preview.Source = EDataSource.None;
|
||||
_Song.ShortEnd.Source = EDataSource.None;
|
||||
|
||||
var headerFlags = new EHeaderFlags();
|
||||
StreamReader sr = null;
|
||||
_LineNr = 0;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, _Song.Encoding, true);
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
_LineNr++;
|
||||
if (line == "")
|
||||
continue;
|
||||
if (!line[0].Equals('#'))
|
||||
break;
|
||||
|
||||
int pos = line.IndexOf(":", StringComparison.Ordinal);
|
||||
|
||||
if (pos <= 1)
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
continue;
|
||||
}
|
||||
string identifier = line.Substring(1, pos - 1).Trim().ToUpper();
|
||||
if (identifier.Contains(" "))
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
continue;
|
||||
}
|
||||
string value = line.Substring(pos + 1).Trim();
|
||||
|
||||
if (value == "")
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
_LogWarning("Empty value skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (identifier)
|
||||
{
|
||||
case "ENCODING":
|
||||
Encoding newEncoding = value.GetEncoding();
|
||||
_Song.ManualEncoding = true;
|
||||
if (!newEncoding.Equals(sr.CurrentEncoding))
|
||||
{
|
||||
if (useSetEncoding)
|
||||
{
|
||||
_LogWarning("Duplicate encoding ignored");
|
||||
continue;
|
||||
}
|
||||
sr.Dispose();
|
||||
sr = null;
|
||||
_Song.Encoding = newEncoding;
|
||||
return ReadHeader(true);
|
||||
}
|
||||
break;
|
||||
case "TITLE":
|
||||
_Song.Title = value;
|
||||
headerFlags |= EHeaderFlags.Title;
|
||||
break;
|
||||
case "ARTIST":
|
||||
_Song.Artist = value;
|
||||
headerFlags |= EHeaderFlags.Artist;
|
||||
break;
|
||||
case "TITLE-ON-SORTING":
|
||||
_Song.TitleSorting = value;
|
||||
break;
|
||||
case "ARTIST-ON-SORTING":
|
||||
_Song.ArtistSorting = value;
|
||||
break;
|
||||
case "CREATOR":
|
||||
case "AUTHOR":
|
||||
case "AUTOR":
|
||||
_Song.Creator = value;
|
||||
break;
|
||||
case "VERSION":
|
||||
_Song.Version = value;
|
||||
break;
|
||||
case "SOURCE":
|
||||
case "YOUTUBE":
|
||||
_Song.Source = value;
|
||||
break;
|
||||
case "MP3":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
{
|
||||
_Song.MP3FileName = value;
|
||||
headerFlags |= EHeaderFlags.MP3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LogError("Can't find audio file: " + Path.Combine(_Song.Folder, value));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "BPM":
|
||||
if (CHelper.TryParse(value, out _Song.BPM))
|
||||
{
|
||||
_Song.BPM *= _BPMFactor;
|
||||
headerFlags |= EHeaderFlags.BPM;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid BPM value");
|
||||
break;
|
||||
case "EDITION":
|
||||
if (value.Length > 1)
|
||||
_Song.Editions.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid edition");
|
||||
break;
|
||||
case "GENRE":
|
||||
if (value.Length > 1)
|
||||
_Song.Genres.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid genre");
|
||||
break;
|
||||
case "ALBUM":
|
||||
_Song.Album = value;
|
||||
break;
|
||||
case "YEAR":
|
||||
int num;
|
||||
if (value.Length == 4 && int.TryParse(value, out num) && num > 0)
|
||||
_Song.Year = value;
|
||||
else
|
||||
_LogWarning("Invalid year");
|
||||
break;
|
||||
case "LANGUAGE":
|
||||
if (value.Length > 1)
|
||||
_Song.Languages.Add(value);
|
||||
else
|
||||
_LogWarning("Invalid language");
|
||||
break;
|
||||
case "COMMENT":
|
||||
if (!String.IsNullOrEmpty(_Song._Comment))
|
||||
_Song._Comment += "\r\n";
|
||||
_Song._Comment += value;
|
||||
break;
|
||||
case "GAP":
|
||||
if (CHelper.TryParse(value, out _Song.Gap))
|
||||
_Song.Gap /= 1000f;
|
||||
else
|
||||
_LogWarning("Invalid gap");
|
||||
break;
|
||||
case "COVER":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.CoverFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find cover file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "BACKGROUND":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.BackgroundFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find background file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "VIDEO":
|
||||
if (File.Exists(Path.Combine(_Song.Folder, value)))
|
||||
_Song.VideoFileName = value;
|
||||
else
|
||||
_LogWarning("Can't find video file: " + Path.Combine(_Song.Folder, value));
|
||||
break;
|
||||
case "VIDEOGAP":
|
||||
if (!CHelper.TryParse(value, out _Song.VideoGap))
|
||||
_LogWarning("Invalid videogap");
|
||||
break;
|
||||
case "VIDEOASPECT":
|
||||
if (!CHelper.TryParse(value, out _Song.VideoAspect, true))
|
||||
_LogWarning("Invalid videoaspect");
|
||||
break;
|
||||
case "START":
|
||||
if (!CHelper.TryParse(value, out _Song.Start))
|
||||
_LogWarning("Invalid start");
|
||||
break;
|
||||
case "END":
|
||||
if (CHelper.TryParse(value, out _Song.Finish))
|
||||
_Song.Finish /= 1000f;
|
||||
else
|
||||
_LogWarning("Invalid end");
|
||||
break;
|
||||
case "PREVIEWSTART":
|
||||
if (CHelper.TryParse(value, out _Song.Preview.StartTime) && _Song.Preview.StartTime >= 0f)
|
||||
_Song.Preview.Source = EDataSource.Tag;
|
||||
else
|
||||
_LogWarning("Invalid previewstart");
|
||||
break;
|
||||
case "PREVIEW":
|
||||
if (CHelper.TryParse(value, out _Song.Preview.StartTime) && _Song.Preview.StartTime >= 0f)
|
||||
{
|
||||
//This is stored in ms not like PREVIEWSTART!
|
||||
_Song.Preview.StartTime /= 1000f;
|
||||
_Song.Preview.Source = EDataSource.Tag;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid previewstart");
|
||||
break;
|
||||
case "MEDLEYSTARTBEAT":
|
||||
if (int.TryParse(value, out _Song.Medley.StartBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyStartBeat;
|
||||
else
|
||||
_LogWarning("Invalid medleystartbeat");
|
||||
break;
|
||||
case "MEDLEYENDBEAT":
|
||||
if (int.TryParse(value, out _Song.Medley.EndBeat))
|
||||
headerFlags |= EHeaderFlags.MedleyEndBeat;
|
||||
else
|
||||
_LogWarning("Invalid medleyendbeat");
|
||||
break;
|
||||
case "ENDSHORT":
|
||||
if ((headerFlags & EHeaderFlags.BPM) != 0)
|
||||
{
|
||||
int endTime;
|
||||
if (int.TryParse(value, out endTime) || endTime < 0)
|
||||
{
|
||||
_Song.ShortEnd.EndBeat = (int)CBase.Game.GetBeatFromTime(endTime / 1000f, _Song.BPM, _Song.Gap);
|
||||
_Song.ShortEnd.Source = EDataSource.Tag;
|
||||
}
|
||||
else
|
||||
_LogWarning("Invalid medleyendbeat");
|
||||
}
|
||||
break;
|
||||
case "CALCMEDLEY":
|
||||
if (value.ToUpper() == "OFF")
|
||||
_Song._CalculateMedley = false;
|
||||
break;
|
||||
case "RELATIVE":
|
||||
if (value.ToUpper() == "YES")
|
||||
_Song.Relative = true;
|
||||
break;
|
||||
case "RESOLUTION":
|
||||
case "NOTESGAP":
|
||||
//Outdated/not used
|
||||
_Song.UnknownTags.Add(line);
|
||||
break;
|
||||
default:
|
||||
if (identifier.StartsWith("DUETSINGER"))
|
||||
{
|
||||
identifier = identifier.Substring(10);
|
||||
if (identifier.StartsWith("P")) // fix for missing "P"
|
||||
identifier = "P" + identifier;
|
||||
}
|
||||
if (identifier.StartsWith("P"))
|
||||
{
|
||||
int player;
|
||||
if (int.TryParse(identifier.Substring(1).Trim(), out player))
|
||||
{
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
_Song.Notes.VoiceNames[curPlayer] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_Song.UnknownTags.Add(line);
|
||||
_LogWarning("Unknown tag: #" + identifier);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} //end of while
|
||||
|
||||
if (sr.EndOfStream)
|
||||
{
|
||||
//No other data then header
|
||||
_LogError("Lyrics/Notes missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Title) == 0)
|
||||
{
|
||||
_LogError("Title tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.Artist) == 0)
|
||||
{
|
||||
_LogError("Artist tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MP3) == 0)
|
||||
{
|
||||
_LogError("MP3 tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.BPM) == 0)
|
||||
{
|
||||
_LogError("BPM tag missing", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
#region check medley tags
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
if (_Song.Medley.StartBeat > _Song.Medley.EndBeat)
|
||||
{
|
||||
_LogError("MedleyStartBeat is bigger than MedleyEndBeat in file", false);
|
||||
headerFlags = headerFlags - EHeaderFlags.MedleyStartBeat - EHeaderFlags.MedleyEndBeat;
|
||||
}
|
||||
}
|
||||
|
||||
if (_Song.Preview.Source == EDataSource.None)
|
||||
{
|
||||
//PreviewStart is not set or <=0
|
||||
_Song.Preview.StartTime = (headerFlags & EHeaderFlags.MedleyStartBeat) != 0 ? CBase.Game.GetTimeFromBeats(_Song.Medley.StartBeat, _Song.BPM) : 0f;
|
||||
}
|
||||
|
||||
if ((headerFlags & EHeaderFlags.MedleyStartBeat) != 0 && (headerFlags & EHeaderFlags.MedleyEndBeat) != 0)
|
||||
{
|
||||
_Song.Medley.Source = EDataSource.Tag;
|
||||
_Song.Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime();
|
||||
_Song.Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime();
|
||||
}
|
||||
#endregion check medley tags
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
_LogError("Error reading txt header" + e.Message, false);
|
||||
return false;
|
||||
}
|
||||
_Song.Encoding = sr.CurrentEncoding;
|
||||
sr.Dispose();
|
||||
_Song._CheckFiles();
|
||||
|
||||
CBase.DataBase.GetDataBaseSongInfos(_Song.Artist, _Song.Title, out _Song.NumPlayed, out _Song.DateAdded, out _Song.DataBaseSongID);
|
||||
|
||||
//Before saving this tags to .txt: Check, if ArtistSorting and Artist are equal, then don't save this tag.
|
||||
if (String.IsNullOrEmpty(_Song.ArtistSorting))
|
||||
_Song.ArtistSorting = _Song.Artist;
|
||||
|
||||
if (String.IsNullOrEmpty(_Song.TitleSorting))
|
||||
_Song.TitleSorting = _Song.Title;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum ENoteReadMode
|
||||
{
|
||||
Normal,
|
||||
ZeroBased,
|
||||
OneBased
|
||||
}
|
||||
|
||||
private class CAutoChanges
|
||||
{
|
||||
public int ZeroLengthNoteCt;
|
||||
public int OverlapNoteCt;
|
||||
public int NoTextNoteCt;
|
||||
public int NoLengthBreakCt;
|
||||
public int AjustedBreakCt;
|
||||
public int InvalidPosBreakCt;
|
||||
|
||||
public bool IsModified
|
||||
{
|
||||
get { return ZeroLengthNoteCt + OverlapNoteCt + NoTextNoteCt + NoLengthBreakCt + AjustedBreakCt + InvalidPosBreakCt > 0; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = "";
|
||||
int skippedNotesCt = ZeroLengthNoteCt + OverlapNoteCt + NoTextNoteCt;
|
||||
if (skippedNotesCt > 0)
|
||||
result += "Skipped " + skippedNotesCt + " notes (0-Length: " + ZeroLengthNoteCt + ", Overlapping: " + OverlapNoteCt + ", No text: " + NoTextNoteCt + ")\r\n";
|
||||
if (InvalidPosBreakCt > 0)
|
||||
result += "Skipped " + InvalidPosBreakCt + " line breaks (Invalid position)\r\n";
|
||||
int adjustedBreakCt = AjustedBreakCt + NoLengthBreakCt;
|
||||
if (adjustedBreakCt > 0)
|
||||
result += "Adjusted " + adjustedBreakCt + " line breaks (Overlapping previous note: " + AjustedBreakCt + ", No length: " + NoLengthBreakCt + ")\r\n";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private ENoteReadMode _CurrentReadMode = ENoteReadMode.Normal;
|
||||
private const int _MaxZeroNoteCt = 1;
|
||||
private const int _MaxOverlapNoteCt = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Read notes. First try to read notes normally (assume standard)<br/>
|
||||
/// If there are more than _MaxZeroNoteCt with length < 1, try to read notes adding 1 to length<br/>
|
||||
/// Then if there are more than _MaxOverlapNoteCt fallback to first version ignoring notes with length < 1
|
||||
/// </summary>
|
||||
/// <param name="forceReload"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadNotes(bool forceReload = false)
|
||||
{
|
||||
//Skip loading if already done and no reload is forced
|
||||
if (_Song.NotesLoaded && !forceReload)
|
||||
return true;
|
||||
|
||||
string filePath = Path.Combine(_Song.Folder, _Song.FileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
_LogError("The file does not exist", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
int currentBeat = 0; //Used for relative songs
|
||||
CSongNote lastNote = null; //Holds last parsed note. Get's reset on player change
|
||||
bool endFound = false; // True if end tag was found
|
||||
|
||||
int player = 1;
|
||||
_LineNr = 0;
|
||||
|
||||
char[] trimChars = {' ', ':'};
|
||||
char[] splitChars = {' '};
|
||||
|
||||
var changesMade = new CAutoChanges();
|
||||
|
||||
StreamReader sr = null;
|
||||
try
|
||||
{
|
||||
sr = new StreamReader(filePath, _Song.Encoding, true);
|
||||
|
||||
_Song.Notes.Reset();
|
||||
|
||||
//Search for Note Beginning
|
||||
while (!sr.EndOfStream && !endFound)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
_LineNr++;
|
||||
|
||||
if (String.IsNullOrEmpty(line))
|
||||
continue;
|
||||
|
||||
char tag = line[0];
|
||||
//Remove tag and potential space
|
||||
line = (line.Length >= 2 && line[1] == ' ') ? line.Substring(2) : line.Substring(1);
|
||||
|
||||
int beat, length;
|
||||
switch (tag)
|
||||
{
|
||||
case '#':
|
||||
continue;
|
||||
case 'E':
|
||||
endFound = true;
|
||||
break;
|
||||
case 'P':
|
||||
line = line.Trim(trimChars);
|
||||
|
||||
if (!int.TryParse(line, out player))
|
||||
{
|
||||
_LogError("Wrong or missing number after \"P\"");
|
||||
return false;
|
||||
}
|
||||
currentBeat = 0;
|
||||
lastNote = null;
|
||||
break;
|
||||
case ':':
|
||||
case '*':
|
||||
case 'F':
|
||||
string[] noteData = line.Split(splitChars, 4);
|
||||
if (noteData.Length < 4)
|
||||
{
|
||||
if (noteData.Length == 3)
|
||||
{
|
||||
_LogWarning("Ignored note without text");
|
||||
changesMade.NoTextNoteCt++;
|
||||
continue;
|
||||
}
|
||||
_LogError("Invalid note found");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
int tone;
|
||||
if (!int.TryParse(noteData[0], out beat) || !int.TryParse(noteData[1], out length) || !int.TryParse(noteData[2], out tone))
|
||||
{
|
||||
_LogError("Invalid note found (non-numeric values)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
string text = noteData[3].TrimMultipleWs();
|
||||
if (text == "")
|
||||
{
|
||||
_LogWarning("Ignored note without text");
|
||||
changesMade.NoTextNoteCt++;
|
||||
continue;
|
||||
}
|
||||
if (_CurrentReadMode == ENoteReadMode.ZeroBased)
|
||||
length++;
|
||||
if (length < 1)
|
||||
{
|
||||
changesMade.ZeroLengthNoteCt++;
|
||||
if (_CurrentReadMode == ENoteReadMode.Normal && changesMade.ZeroLengthNoteCt > _MaxZeroNoteCt && changesMade.OverlapNoteCt <= _MaxOverlapNoteCt)
|
||||
{
|
||||
_LogWarning("Found more than " + _MaxZeroNoteCt + " note with length < 1. Trying alternative read mode.");
|
||||
_CurrentReadMode = ENoteReadMode.ZeroBased;
|
||||
sr.Dispose();
|
||||
return ReadNotes(true);
|
||||
}
|
||||
_LogWarning("Ignored note with length < 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
ENoteType noteType;
|
||||
|
||||
if (tag.Equals('*'))
|
||||
noteType = ENoteType.Golden;
|
||||
else if (tag.Equals('F'))
|
||||
noteType = ENoteType.Freestyle;
|
||||
else
|
||||
noteType = ENoteType.Normal;
|
||||
|
||||
if (_Song.Relative)
|
||||
beat += currentBeat;
|
||||
|
||||
bool ignored = false;
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
{
|
||||
//Create the note here as we want independent instances in the lines. Otherwhise we can't modify them later
|
||||
lastNote = new CSongNote(beat, length, tone, text, noteType);
|
||||
if (!_AddNote(curPlayer, lastNote))
|
||||
{
|
||||
if (!ignored)
|
||||
{
|
||||
ignored = true;
|
||||
changesMade.OverlapNoteCt++;
|
||||
if (changesMade.OverlapNoteCt > _MaxOverlapNoteCt && _CurrentReadMode == ENoteReadMode.ZeroBased)
|
||||
{
|
||||
_LogWarning("Found more than " + _MaxOverlapNoteCt + " overlapping notes. Using standard mode.");
|
||||
_CurrentReadMode = ENoteReadMode.OneBased;
|
||||
sr.Dispose();
|
||||
return ReadNotes(true);
|
||||
}
|
||||
}
|
||||
_LogWarning("Ignored note for player " + (curPlayer + 1) + " because it overlaps with other note");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
string[] lineBreakData = line.Split(splitChars);
|
||||
if (lineBreakData.Length < 1)
|
||||
{
|
||||
_LogError("Invalid line break found (No beat)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
if (!int.TryParse(lineBreakData[0], out beat))
|
||||
{
|
||||
_LogError("Invalid line break found (Non-numeric value)");
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_Song.Relative)
|
||||
{
|
||||
beat += currentBeat;
|
||||
if (lineBreakData.Length < 2 || !int.TryParse(lineBreakData[1], out length))
|
||||
{
|
||||
_LogWarning("Missing line break length");
|
||||
changesMade.NoLengthBreakCt++;
|
||||
currentBeat = beat;
|
||||
}
|
||||
else
|
||||
currentBeat += length;
|
||||
}
|
||||
|
||||
if (lastNote != null && beat <= lastNote.EndBeat)
|
||||
{
|
||||
_LogWarning("Line break is before previous note end. Adjusted.");
|
||||
changesMade.AjustedBreakCt++;
|
||||
if (_Song.Relative)
|
||||
currentBeat += lastNote.EndBeat - beat + 1;
|
||||
beat = lastNote.EndBeat + 1;
|
||||
}
|
||||
|
||||
if (beat < 1)
|
||||
{
|
||||
_LogWarning("Ignored line break because position is < 1");
|
||||
changesMade.InvalidPosBreakCt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (int curPlayer in player.GetSetBits())
|
||||
{
|
||||
if (!_NewSentence(curPlayer, beat))
|
||||
_LogWarning("Ignored line break for player " + (curPlayer + 1) + " (Overlapping or duplicate)");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_LogError("Unexpected or missing character (" + tag + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(i);
|
||||
int emptyLines = voice.RemoveEmptyLines();
|
||||
if (emptyLines > 0)
|
||||
_LogWarning("Removed " + emptyLines + " empty lines from P" + ". This often indicates a problem with the line breaks in the file", false);
|
||||
voice.UpdateTimings();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_LogError("An unhandled exception occured (" + e.Message + ")");
|
||||
if (sr != null)
|
||||
sr.Dispose();
|
||||
return false;
|
||||
}
|
||||
sr.Dispose();
|
||||
try
|
||||
{
|
||||
_Song._FindRefrain();
|
||||
_Song._FindShortEnd();
|
||||
_Song.NotesLoaded = true;
|
||||
if (_Song.IsDuet)
|
||||
_Song._CheckDuet();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_LogError("An unhandled exception occured (" + e.Message + ")", false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (changesMade.IsModified)
|
||||
{
|
||||
string msg = "Automatic changes have been made to " + filePath + " Please check result!\r\n" + changesMade;
|
||||
CBase.Log.LogError("Warning: " + msg);
|
||||
if (CBase.Config.GetSaveModifiedSongs() == EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
string name = Path.GetFileNameWithoutExtension(_Song.FileName);
|
||||
_Song.Save(Path.Combine(_Song.Folder, name + ".fix"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool _AddNote(int player, CSongNote note)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(player);
|
||||
return voice.AddNote(note, false);
|
||||
}
|
||||
|
||||
private bool _NewSentence(int player, int start)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(player);
|
||||
return voice.AddLine(start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,20 +25,20 @@ namespace VocaluxeLib.Songs
|
||||
#region Contructors
|
||||
public CSongNote(CSongNote note) : base(note)
|
||||
{
|
||||
NoteType = note.NoteType;
|
||||
Type = note.Type;
|
||||
Text = note.Text;
|
||||
}
|
||||
|
||||
public CSongNote(int startBeat, int duration, int tone, string text, ENoteType noteType)
|
||||
: base(startBeat, duration, tone)
|
||||
{
|
||||
NoteType = noteType;
|
||||
Type = noteType;
|
||||
Text = text;
|
||||
}
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
public ENoteType NoteType { get; set; }
|
||||
public ENoteType Type { get; set; }
|
||||
|
||||
public string Text { get; set; }
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace VocaluxeLib.Songs
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (NoteType)
|
||||
switch (Type)
|
||||
{
|
||||
case ENoteType.Normal:
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace VocaluxeLib.Songs
|
||||
{
|
||||
public partial class CSong
|
||||
{
|
||||
private class CSongWriter
|
||||
{
|
||||
private readonly CSong _Song;
|
||||
private TextWriter _Tw;
|
||||
|
||||
public CSongWriter(CSong song)
|
||||
{
|
||||
_Song = song;
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, string value)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(value))
|
||||
_Tw.WriteLine("#" + id.ToUpper() + ":" + value);
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, bool value)
|
||||
{
|
||||
if (value)
|
||||
_WriteHeaderEntry(id, "YES");
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, float value, float def = 0f)
|
||||
{
|
||||
if (Math.Abs(value - def) > 0.0001)
|
||||
_WriteHeaderEntry(id, value.ToInvariantString());
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntry(string id, int value, int def = 0)
|
||||
{
|
||||
if (value != def)
|
||||
_WriteHeaderEntry(id, value.ToString());
|
||||
}
|
||||
|
||||
private void _WriteHeaderEntrys(string id, ICollection<string> value)
|
||||
{
|
||||
if (value == null || value.Count <= 0)
|
||||
return;
|
||||
foreach (String val in value)
|
||||
_WriteHeaderEntry(id, val);
|
||||
}
|
||||
|
||||
private void _WriteHeader()
|
||||
{
|
||||
if (_Song.ManualEncoding)
|
||||
_WriteHeaderEntry("ENCODING", _Song.Encoding.GetEncodingName());
|
||||
_WriteHeaderEntry("CREATOR", _Song.Creator);
|
||||
_WriteHeaderEntry("VERSION", _Song.Version);
|
||||
_WriteHeaderEntry("SOURCE", _Song.Source);
|
||||
if (!String.IsNullOrEmpty(_Song._Comment))
|
||||
{
|
||||
string comment = _Song._Comment.Replace("\r\n", "\n").Replace('\r', '\n');
|
||||
char[] splitChar = {'\n'};
|
||||
_WriteHeaderEntrys("COMMENT", comment.Split(splitChar));
|
||||
}
|
||||
_WriteHeaderEntry("TITLE", _Song.Title);
|
||||
_WriteHeaderEntry("ARTIST", _Song.Artist);
|
||||
if (!_Song.Title.Equals(_Song.TitleSorting))
|
||||
_WriteHeaderEntry("TITLE-ON-SORTING", _Song.TitleSorting);
|
||||
if (!_Song.Artist.Equals(_Song.ArtistSorting))
|
||||
_WriteHeaderEntry("ARTIST-ON-SORTING", _Song.ArtistSorting);
|
||||
_WriteHeaderEntrys("EDITION", _Song.Editions);
|
||||
_WriteHeaderEntrys("GENRE", _Song.Genres);
|
||||
_WriteHeaderEntrys("LANGUAGE", _Song.Languages);
|
||||
_WriteHeaderEntry("ALBUM", _Song.Album);
|
||||
_WriteHeaderEntry("YEAR", _Song.Year);
|
||||
_WriteHeaderEntry("MP3", _Song.MP3FileName);
|
||||
_WriteHeaderEntry("COVER", _Song.CoverFileName);
|
||||
_WriteHeaderEntry("BACKGROUND", _Song.BackgroundFileName);
|
||||
_WriteHeaderEntry("VIDEO", _Song.VideoFileName);
|
||||
_WriteHeaderEntry("VIDEOGAP", _Song.VideoGap);
|
||||
if (_Song.VideoAspect != EAspect.Crop)
|
||||
_WriteHeaderEntry("VIDEOASPECT", _Song.VideoAspect.ToString());
|
||||
_WriteHeaderEntry("RELATIVE", _Song.Relative);
|
||||
_WriteHeaderEntry("BPM", _Song.BPM / _BPMFactor);
|
||||
_WriteHeaderEntry("GAP", (int)(_Song.Gap * 1000f));
|
||||
if (_Song.Preview.Source == EDataSource.Tag)
|
||||
_WriteHeaderEntry("PREVIEWSTART", _Song.Preview.StartTime);
|
||||
_WriteHeaderEntry("START", _Song.Start);
|
||||
_WriteHeaderEntry("END", (int)(_Song.Finish * 1000f));
|
||||
if (_Song.ShortEnd.Source == EDataSource.Tag)
|
||||
_WriteHeaderEntry("ENDSHORT", (int)(CBase.Game.GetTimeFromBeats(_Song.ShortEnd.EndBeat, _Song.BPM) + _Song.Gap) * 1000);
|
||||
if (!_Song._CalculateMedley)
|
||||
_WriteHeaderEntry("CALCMEDLEY", "OFF");
|
||||
if (_Song.Medley.Source == EDataSource.Tag)
|
||||
{
|
||||
_WriteHeaderEntry("MEDLEYSTARTBEAT", _Song.Medley.StartBeat);
|
||||
_WriteHeaderEntry("MEDLEYENDBEAT", _Song.Medley.EndBeat);
|
||||
}
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
if (_Song.Notes.VoiceNames.IsSet(i))
|
||||
_WriteHeaderEntry("P" + i, _Song.Notes.VoiceNames[i]);
|
||||
}
|
||||
foreach (string addLine in _Song.UnknownTags)
|
||||
_Tw.WriteLine(addLine);
|
||||
}
|
||||
|
||||
private void _WriteNotes()
|
||||
{
|
||||
for (int i = 0; i < _Song.Notes.VoiceCount; i++)
|
||||
{
|
||||
CVoice voice = _Song.Notes.GetVoice(i);
|
||||
if (_Song.Notes.VoiceCount > 1)
|
||||
_Tw.WriteLine("P" + Math.Pow(2, i));
|
||||
bool firstLine = true;
|
||||
int currentBeat = 0;
|
||||
foreach (CSongLine line in voice.Lines)
|
||||
{
|
||||
if (!firstLine)
|
||||
{
|
||||
string lineTxt = "- " + (line.StartBeat - currentBeat);
|
||||
if (_Song.Relative)
|
||||
{
|
||||
lineTxt += " " + (line.FirstNoteBeat - currentBeat);
|
||||
currentBeat = line.FirstNoteBeat;
|
||||
}
|
||||
_Tw.WriteLine(lineTxt);
|
||||
}
|
||||
else
|
||||
firstLine = false;
|
||||
foreach (CSongNote note in line.Notes)
|
||||
{
|
||||
string tag;
|
||||
switch (note.Type)
|
||||
{
|
||||
case ENoteType.Normal:
|
||||
tag = ":";
|
||||
break;
|
||||
case ENoteType.Golden:
|
||||
tag = "*";
|
||||
break;
|
||||
case ENoteType.Freestyle:
|
||||
tag = "F";
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("Note type " + note.Type);
|
||||
}
|
||||
_Tw.WriteLine(tag + " " + (note.StartBeat - currentBeat) + " " + note.Duration + " " + note.Tone + " " + note.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
_Tw.WriteLine("E");
|
||||
}
|
||||
|
||||
public bool SaveFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
_Tw = new StreamWriter(filePath, false, _Song.Encoding);
|
||||
_WriteHeader();
|
||||
_WriteNotes();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CBase.Log.LogError("Unhandled exception while writing " + filePath + ": " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace VocaluxeLib.Songs
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public double Points;
|
||||
public new double Points;
|
||||
// for drawing player notes
|
||||
public bool Hit
|
||||
{
|
||||
|
||||
+85
-14
@@ -15,6 +15,7 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -67,7 +68,11 @@ namespace VocaluxeLib.Songs
|
||||
}
|
||||
|
||||
#region Methods
|
||||
//Find last line with StartBeat<=Beat
|
||||
/// <summary>
|
||||
/// Find last line with StartBeat<=Beat
|
||||
/// </summary>
|
||||
/// <param name="beat"></param>
|
||||
/// <returns></returns>
|
||||
public int FindPreviousLine(int beat)
|
||||
{
|
||||
//If no line -> No previous line
|
||||
@@ -92,15 +97,49 @@ namespace VocaluxeLib.Songs
|
||||
return start;
|
||||
}
|
||||
|
||||
public void AddLine(CSongLine line)
|
||||
public bool AddLine(CSongLine line, bool updateTimings = true)
|
||||
{
|
||||
if (_Lines.Count == 0)
|
||||
_Lines.Add(line);
|
||||
else
|
||||
{
|
||||
int insPos = FindPreviousLine(line.StartBeat);
|
||||
//Check if previous line ends before this one
|
||||
if (insPos >= 0 && _Lines[insPos].LastNoteBeat > line.StartBeat)
|
||||
return false;
|
||||
//Check if next line starts before this one ends
|
||||
if (insPos + 1 < _Lines.Count && _Lines[insPos + 1].FirstNoteBeat < line.LastNoteBeat)
|
||||
return false;
|
||||
_Lines.Insert(insPos + 1, line);
|
||||
}
|
||||
if (updateTimings)
|
||||
UpdateTimings();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddLine(int startBeat)
|
||||
{
|
||||
int insPos = FindPreviousLine(startBeat);
|
||||
//Check for actual notes (startbeat may be lower than first note)
|
||||
while (insPos >= 0 && _Lines[insPos].NoteCount > 0 && _Lines[insPos].FirstNoteBeat > startBeat)
|
||||
insPos--;
|
||||
CSongLine line = new CSongLine {StartBeat = startBeat};
|
||||
if (insPos >= 0)
|
||||
{
|
||||
CSongLine prevLine = _Lines[insPos];
|
||||
//We already have a line break here
|
||||
if (prevLine.StartBeat == startBeat && (prevLine.NoteCount==0 || prevLine.FirstNoteBeat == startBeat))
|
||||
return false;
|
||||
//Maybe we have to split the previous line
|
||||
while (prevLine.NoteCount > 0 && prevLine.LastNote.StartBeat >= startBeat)
|
||||
{
|
||||
//throw new Exception("This should not happen on song loading!");
|
||||
line.AddNote(prevLine.LastNote);
|
||||
prevLine.DeleteNote(prevLine.NoteCount - 1);
|
||||
}
|
||||
}
|
||||
_Lines.Insert(insPos + 1, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DeleteLine(int index)
|
||||
@@ -119,15 +158,26 @@ namespace VocaluxeLib.Songs
|
||||
_Lines.Clear();
|
||||
}
|
||||
|
||||
public bool AddNote(CSongNote note, bool updateTimings = false)
|
||||
public bool AddNote(CSongNote note, bool updateTimings = true)
|
||||
{
|
||||
int lineIndex = FindPreviousLine(note.StartBeat);
|
||||
if (lineIndex + 1 < _Lines.Count && _Lines[lineIndex + 1].FirstNoteBeat < note.EndBeat) //First note in next line starts before this one ends
|
||||
return false;
|
||||
if (lineIndex < 0)
|
||||
{
|
||||
//Note is before ALL lines
|
||||
var line = new CSongLine {StartBeat = note.StartBeat};
|
||||
line.AddNote(note);
|
||||
_Lines.Insert(0, line);
|
||||
if (_Lines.Count > 0)
|
||||
{
|
||||
//Add to first line
|
||||
if (!_Lines[0].AddNote(note))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var line = new CSongLine();
|
||||
line.AddNote(note);
|
||||
_Lines.Add(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -139,24 +189,27 @@ namespace VocaluxeLib.Songs
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool InsertNote(CSongNote note, int lineIndex, bool updateTimings = false)
|
||||
/*Check this first for consistency (next line might be affected)
|
||||
* public bool InsertNote(CSongNote note, int lineIndex, bool updateTimings = false)
|
||||
{
|
||||
if (_Lines.Count > lineIndex && _Lines[lineIndex].StartBeat <= note.StartBeat)
|
||||
{
|
||||
_Lines[lineIndex].AddNote(note);
|
||||
if (!_Lines[lineIndex].AddNote(note))
|
||||
return false;
|
||||
if (updateTimings)
|
||||
UpdateTimings();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
public void UpdateTimings()
|
||||
{
|
||||
CSongNote lastNote;
|
||||
|
||||
if (_Lines.Count > 0)
|
||||
_Lines[0].StartBeat = -10000;
|
||||
if (_Lines.Count == 0)
|
||||
return;
|
||||
_Lines[0].StartBeat = -10000;
|
||||
|
||||
for (int i = 1; i < _Lines.Count; i++)
|
||||
{
|
||||
@@ -191,11 +244,24 @@ namespace VocaluxeLib.Songs
|
||||
_Lines[i].StartBeat = s;
|
||||
_Lines[i - 1].EndBeat = min;
|
||||
}
|
||||
else if (firstNote != null)
|
||||
{
|
||||
_Lines[i - 1].EndBeat = Math.Min(_Lines[i - 1].StartBeat, firstNote.StartBeat - 2);
|
||||
_Lines[i].StartBeat = Math.Max(_Lines[i - 1].EndBeat, firstNote.StartBeat - 2);
|
||||
}
|
||||
else if (lastNote != null)
|
||||
{
|
||||
_Lines[i - 1].EndBeat = lastNote.EndBeat;
|
||||
_Lines[i].StartBeat = Math.Max(lastNote.EndBeat, _Lines[i].StartBeat); //Prefer current setting
|
||||
}
|
||||
else
|
||||
{
|
||||
//No note
|
||||
_Lines[i - 1].EndBeat = _Lines[i - 1].StartBeat; //Assume at least startbeats were set right
|
||||
}
|
||||
}
|
||||
|
||||
lastNote = _Lines[_Lines.Count - 1].LastNote;
|
||||
if (lastNote != null)
|
||||
_Lines[_Lines.Count - 1].EndBeat = lastNote.EndBeat;
|
||||
_Lines[_Lines.Count - 1].EndBeat = Math.Max(_Lines[_Lines.Count - 1].LastNoteBeat, _Lines[_Lines.Count - 1].StartBeat); //Use note or (when not set) start beat
|
||||
}
|
||||
|
||||
public void SetMedley(int startBeat, int endBeat)
|
||||
@@ -204,5 +270,10 @@ namespace VocaluxeLib.Songs
|
||||
line.SetMedley(startBeat, endBeat);
|
||||
}
|
||||
#endregion Methods
|
||||
|
||||
public int RemoveEmptyLines()
|
||||
{
|
||||
return _Lines.RemoveAll(line => line.NoteCount == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="IBasic.cs" />
|
||||
<Compile Include="Menu\CBackground.cs" />
|
||||
@@ -174,9 +175,11 @@
|
||||
<Compile Include="Menu\SongMenu\CSongMenuList.cs" />
|
||||
<Compile Include="Menu\SongMenu\CSongMenuTileBoard.cs" />
|
||||
<Compile Include="Menu\SongMenu\ISongMenu.cs" />
|
||||
<Compile Include="Songs\CSongWriter.cs" />
|
||||
<Compile Include="Songs\CSungLine.cs" />
|
||||
<Compile Include="Songs\CSungNote.cs" />
|
||||
<Compile Include="Songs\CVoice.cs" />
|
||||
<Compile Include="Songs\CSongLoader.cs" />
|
||||
<Compile Include="Structs.cs" />
|
||||
<Compile Include="PartyModes\CPartyMode.cs" />
|
||||
<Compile Include="PartyModes\CPartyModeNone.cs" />
|
||||
@@ -195,4 +198,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
Reference in new issue
Block a user