aboutsummaryrefslogtreecommitdiffstats
path: root/Medley/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'Medley/src/base')
-rw-r--r--Medley/src/base/UDraw.pas9
-rw-r--r--Medley/src/base/UNote.pas36
-rw-r--r--Medley/src/base/USong.pas329
-rw-r--r--Medley/src/base/USongs.pas19
-rw-r--r--Medley/src/base/UThemes.pas16
5 files changed, 391 insertions, 18 deletions
diff --git a/Medley/src/base/UDraw.pas b/Medley/src/base/UDraw.pas
index 1783986f..8bb2c210 100644
--- a/Medley/src/base/UDraw.pas
+++ b/Medley/src/base/UDraw.pas
@@ -97,6 +97,7 @@ uses
URecord,
UScreenSing,
UScreenSingModi,
+ USong,
UTexture;
procedure SingDrawBackground;
@@ -1387,7 +1388,13 @@ begin
if (CurLyricsTime > 0) and
(LyricsState.TotalTime > 0) then
begin
- LyricsProgress := CurLyricsTime / LyricsState.TotalTime;
+ if ScreenSong.Mode <> smMedley then
+ LyricsProgress := CurLyricsTime / LyricsState.TotalTime
+ else
+ LyricsProgress := (CurLyricsTime - GetTimeFromBeat(CurrentSong.Medley.StartBeat) +
+ CurrentSong.Medley.FadeIn_time) / (GetTimeFromBeat(CurrentSong.Medley.EndBeat) +
+ CurrentSong.Medley.FadeOut_time - GetTimeFromBeat(CurrentSong.Medley.StartBeat) +
+ CurrentSong.Medley.FadeIn_time);
glTexCoord2f((width * LyricsProgress) / 8, 0);
glVertex2f(x + width * LyricsProgress, y);
diff --git a/Medley/src/base/UNote.pas b/Medley/src/base/UNote.pas
index 8e5b709a..bc91c892 100644
--- a/Medley/src/base/UNote.pas
+++ b/Medley/src/base/UNote.pas
@@ -88,13 +88,30 @@ type
Note: array of TPlayerNote;
end;
+ TStats = record
+ Player: array of TPlayer;
+ SongArtist: UTF8String;
+ SongTitle: UTF8String;
+ end;
+
+ TMedleyPlaylist = record
+ Song: array of integer;
+ NumMedleySongs: integer;
+ CurrentMedleySong: integer;
+ ApplausePlayed: boolean;
+ Stats: array of TStats;
+ NumPlayer: integer;
+ end;
+
var
// player and music info
Player: array of TPlayer;
PlayersPlay: integer;
-
+ PlaylistMedley: TMedleyPlaylist;
CurrentSong: TSong;
+ max_song_score_medley: integer;
+ max_song_line_bonus_medley: integer;
const
MAX_SONG_SCORE = 10000; // max. achievable points per song
@@ -463,10 +480,19 @@ begin
// half size notes patch
NoteHit := true;
- if (Ini.LineBonus > 0) then
- MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS
- else
- MaxSongPoints := MAX_SONG_SCORE;
+ if ScreenSong.Mode <> smMedley then
+ begin
+ if (Ini.LineBonus > 0) then
+ MaxSongPoints := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS
+ else
+ MaxSongPoints := MAX_SONG_SCORE;
+ end else
+ begin
+ if (Ini.LineBonus > 0) then
+ MaxSongPoints := max_song_score_medley - max_song_line_bonus_medley
+ else
+ MaxSongPoints := max_song_score_medley;
+ end;
// Note: ScoreValue is the sum of all note values of the song
// (MaxSongPoints / ScoreValue) is the points that a player
diff --git a/Medley/src/base/USong.pas b/Medley/src/base/USong.pas
index c465f198..d4eb714d 100644
--- a/Medley/src/base/USong.pas
+++ b/Medley/src/base/USong.pas
@@ -64,7 +64,8 @@ uses
type
- TSingMode = ( smNormal, smPartyMode, smPlaylistRandom );
+ TSingMode = ( smNormal, smPartyMode, smPlaylistRandom, smMedley );
+ TMedleySource = ( msNone, msCalculated, msTag );
TBPM = record
BPM: real;
@@ -85,6 +86,16 @@ type
Content: UTF8String;
end;
+ TMedley = record
+ Source: TMedleySource; //source of the information
+ StartBeat: integer; //start beat of medley
+ EndBeat: integer; //end beat of medley
+ FadeIn: integer; //start beat of fadein
+ FadeOut: integer; //end beat of fadeout
+ FadeIn_time: real; //FadeIn-Time in seconds
+ FadeOut_time: real; //FadeIn-Time in seconds
+ end;
+
TSong = class
private
FileLineNo : integer; // line, which is read last, for error reporting
@@ -157,6 +168,9 @@ type
MultBPM : integer;
LastError: AnsiString;
+
+ Medley: TMedley; //infos for medley-mode and preview start
+
function GetErrorLineNo: integer;
property ErrorLineNo: integer read GetErrorLineNo;
@@ -168,6 +182,9 @@ type
function Analyse(const ReadCustomTags: Boolean = false): boolean;
function AnalyseXML(): boolean;
procedure Clear();
+ procedure FindRefrainStart;
+ procedure SetMedleyMode;
+ function ReadMedleyFile(MedleyFilePath: IPath): boolean;
end;
implementation
@@ -178,7 +195,7 @@ uses
UIni,
UPathUtils,
UMusic, //needed for Lines
- UNote; //needed for Player
+ UNote;
const
DEFAULT_ENCODING = encAuto;
@@ -461,6 +478,7 @@ begin
Exit;
end;
+ SetLength(Lines, 0); //just a fix.. for medley-mod
SetLength(Lines, 2);
for Count := 0 to High(Lines) do
begin
@@ -589,7 +607,6 @@ begin
if (High(Lines[Count].Line) >= 0) then
Lines[Count].Line[High(Lines[Count].Line)].LastLine := true;
end;
-
Result := true;
end;
@@ -1292,6 +1309,7 @@ begin
Creator := '';
Relative := false;
+ Medley.Source := msNone;
end;
function TSong.Analyse(const ReadCustomTags: Boolean): boolean;
@@ -1310,7 +1328,10 @@ begin
Self.clear;
//Read Header
- Result := Self.ReadTxTHeader(SongFile, ReadCustomTags)
+ Result := Self.ReadTxTHeader(SongFile, ReadCustomTags);
+
+ //Load Song (for testing)
+ Result := Result and Self.LoadSong;
finally
SongFile.Free;
end;
@@ -1318,7 +1339,6 @@ end;
function TSong.AnalyseXML(): boolean;
-
begin
Result := false;
@@ -1331,6 +1351,305 @@ begin
//Read Header
Result := self.ReadXMLHeader( FileName );
+ //Load Song (for testing)
+ Result := Result and self.LoadXMLSong;
+
+end;
+
+
+{* new procedure for preview
+ tries find out the beginning of a refrain *}
+procedure TSong.FindRefrainStart();
+Type
+ TSeries = record
+ start: integer; //Start sentence of series
+ end_: integer; //End sentence of series
+ len: integer; //Length of sentence series
+ end;
+
+var
+ I, J, K, num_lines: integer;
+ sentences: array of UTF8String;
+ series: array of TSeries;
+ temp_series: TSeries;
+ max: integer;
+
+begin
+ if Medley.Source = msTag then
+ Exit;
+
+ num_lines := Length(Lines[0].Line);
+ SetLength(sentences, num_lines);
+
+ //build sentences array
+ for I := 0 to num_lines - 1 do
+ begin
+ sentences[I] := '';
+ for J := 0 to Length(Lines[0].Line[I].Note) - 1 do
+ begin
+ sentences[I] := sentences[I] + Lines[0].Line[I].Note[J].Text;
+ end;
+ end;
+
+ //find equal sentences series
+ SetLength(series, 0);
+
+ for I := 0 to num_lines - 2 do
+ begin
+ for J := I+1 to num_lines - 1 do
+ begin
+ if sentences[I]=sentences[J] then
+ begin
+ temp_series.start := I;
+ temp_series.end_ := I;
+
+ if (J+J-I-1>num_lines-1) then
+ max:=num_lines-1-J
+ else
+ max:=J-I-1;
+
+ for K := 1 to max do
+ begin
+ if sentences[I+K]=sentences[J+K] then
+ temp_series.end_ := I+K
+ else
+ break;
+ end;
+ temp_series.len := temp_series.end_ - temp_series.start + 1;
+ SetLength(series, Length(series)+1);
+ series[Length(series)-1] := temp_series;
+ end;
+ end;
+ end;
+
+ //search for longest sequence
+ if Length(series)>0 then
+ begin
+ max := 0;
+ for I := 0 to Length(series) - 1 do
+ begin
+ if series[I].len > series[max].len then
+ max := I;
+ end;
+ end;
+
+ if (Length(series)>0) and (series[max].len > 3) then
+ begin
+ Medley.Source := msCalculated;
+ Medley.StartBeat := Lines[0].Line[series[max].start].Note[0].Start;
+ end else
+ Medley.Source := msNone;
+end;
+
+//sets a song to medley-mod:
+//converts all unneeded notes into freestyle
+//updates score values
+procedure TSong.SetMedleyMode;
+var
+ pl, line, note: integer;
+ LF: TLineFragment;
+ start: integer;
+ end_: integer;
+begin
+ start := self.Medley.StartBeat;
+ end_ := self.Medley.EndBeat;
+
+ for pl := 0 to Length(Lines) - 1 do
+ begin
+ Lines[pl].ScoreValue := 0;
+ for line := 0 to Length(Lines[pl].Line) - 1 do
+ begin
+ Lines[pl].Line[line].TotalNotes := 0;
+ for note := 0 to Length(Lines[pl].Line[line].Note) - 1 do
+ begin
+ LF := Lines[pl].Line[line].Note[note];
+ if LF.Start < start then //check start
+ Lines[pl].Line[line].Note[note].NoteType := ntFreestyle
+ else if LF.Start>= end_ then //check end
+ Lines[pl].Line[line].Note[note].NoteType := ntFreestyle
+ else
+ begin
+ //add this notes value ("notes length" * "notes scorefactor") to the current songs entire value
+ Inc(Lines[pl].ScoreValue, LF.Length * ScoreFactor[LF.NoteType]);
+ //and to the current lines entire value
+ Inc(Lines[pl].Line[line].TotalNotes, LF.Length * ScoreFactor[LF.NoteType]);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//reads the txtm
+//TODO move this to ReadTXTHeader and implement the MEDLEY-TAGS in txt-file:
+//conversion: START-> MEDLEY_START
+// END-> MEDLEY_END
+// FADE_IN -> MEDLEY_FADE_IN
+// FADE_OUT-> MEDLEY_FADE_OUT
+//TODO: write a tool to convert existing txtm
+function TSong.ReadMedleyFile(MedleyFilePath: IPath): boolean;
+const
+ DEFAULT_FADE_IN_TIME = 10;
+ DEFAULT_FADE_OUT_TIME = 4;
+var
+ Line, Identifier: string;
+ Value: string;
+ SepPos: integer; // separator position
+ Done: byte; // bit-vector of mandatory fields
+ EncFile: IPath; // encoded filename
+ FullFileName: string;
+ LineNo: integer;
+ MedleyFile: TTextFileStream;
+ found_fadeIn, found_fadeOut: boolean;
+
+begin
+ Result := true;
+ Done := 0;
+
+ MedleyFile := TMemTextFileStream.Create(MedleyFilePath, fmOpenRead);
+ FullFileName := MedleyFilePath.ToNative;
+
+ //set standard values
+ found_fadeIn := false;
+ found_fadeOut := false;
+
+ //Read first Line
+ MedleyFile.ReadLine(Line);
+ if (Length(Line) <= 0) then
+ begin
+ Log.LogError('File starts with empty line: ' + FullFileName,
+ 'TSong.ReadMedleyFile');
+ Result := false;
+ Exit;
+ end;
+
+ // check if file begins with a UTF-8 BOM, if so set encoding to UTF-8
+ if (CheckReplaceUTF8BOM(Line)) then
+ Encoding := encUTF8;
+
+ //Read Lines while Line starts with # or its empty
+ while (Length(Line) = 0) or (Line[1] = '#') do
+ begin
+ //Increase Line Number
+ Inc (LineNo);
+ SepPos := Pos(':', Line);
+
+ //Line has no Seperator, ignore non header field
+ if (SepPos = 0) then
+ begin
+ // read next line
+ if (not MedleyFile.ReadLine(Line)) then
+ begin
+ Result := false;
+ Log.LogError('File incomplete or not Ultrastar txtm (A): ' + FullFileName);
+ Break;
+ end;
+ Continue;
+ end;
+
+ //Read Identifier and Value
+ Identifier := UpperCase(Trim(Copy(Line, 2, SepPos - 2))); //Uppercase is for Case Insensitive Checks
+ Value := Trim(Copy(Line, SepPos + 1, Length(Line) - SepPos));
+
+ //Check the Identifier (If Value is given)
+ if (Length(Value) = 0) then
+ begin
+ Log.LogWarn('Empty field "'+Identifier+'" in file ' + FullFileName,
+ 'TSong.ReadMedleyFile');
+ end
+ else
+ begin
+
+ //-----------
+ //Required Attributes
+ //-----------
+
+ if (Identifier = 'START') then
+ begin
+ if TryStrtoInt(Value, self.Medley.StartBeat) then
+ //Add START flag to Done
+ Done := Done or 1;
+ end
+
+ else if (Identifier = 'END') then
+ begin
+ if TryStrtoInt(Value, self.Medley.EndBeat) then
+ //Add END Flag to Done
+ Done := Done or 2;
+ end
+
+ //---------
+ //Additional Header Information
+ //---------
+
+ else if (Identifier = 'FADE_IN') then
+ begin
+ if TryStrtoInt(Value, self.Medley.FadeIn) then
+ found_fadeIn := true;
+ end
+
+ else if (Identifier = 'FADE_OUT') then
+ begin
+ if TryStrtoInt(Value, self.Medley.FadeOut) then
+ found_fadeOut := true;
+ end
+ end; // End check for non-empty Value
+
+ // read next line
+ if (not MedleyFile.ReadLine(Line)) then
+ begin
+ Result := false;
+ Log.LogError('File incomplete or not Ultrastar txtm (A): ' + FullFileName);
+ Break;
+ end;
+ end; // while
+
+ //Check if all Required Values are given
+ if (Done <> 3) then
+ begin
+ Result := false;
+ if (Done and 2) = 0 then //No End Flag
+ Log.LogError('END tag missing: ' + FullFileName)
+ else if (Done and 1) = 0 then //No Start Flag
+ Log.LogError('START tag missing: ' + FullFileName)
+ else //unknown Error
+ Log.LogError('File incomplete or not Ultrastar txtm (B - '+ inttostr(Done) +'): ' + FullFileName);
+
+ Self.Medley.Source := msNone;
+ end else if self.Medley.StartBeat>=self.Medley.EndBeat then
+ begin
+ Log.LogError('Failed to load MEDLEY-TAGS (Start>=End): ' + FullFileName);
+ self.Medley.Source := msNone;
+ Result := false;
+ end else if found_fadeIn and (self.Medley.FadeIn>=self.Medley.StartBeat) then
+ begin
+ Log.LogError('Failed to load MEDLEY-TAGS (FadeIn>=Start): ' + FullFileName);
+ self.Medley.Source := msNone;
+ Result := false;
+ end else if found_fadeOut and (self.Medley.EndBeat>=self.Medley.FadeOut) then
+ begin
+ Log.LogError('Failed to load MEDLEY-TAGS (End>=FadeOut): ' + FullFileName);
+ self.Medley.Source := msNone;
+ Result := false;
+ end else
+ begin
+ self.Medley.Source := msTag;
+ CurrentSong := self;
+ if not found_fadeIn then //set FadeIn if not defined
+ begin // TODO: what if FadeIn < song start?
+ self.Medley.FadeIn := self.Medley.StartBeat - round(GetMidBeat(DEFAULT_FADE_IN_TIME));
+ end;
+ if not found_fadeOut then //set FadeOut if not defined
+ begin // TODO: what if FadeOut > song end?
+ self.Medley.FadeOut := self.Medley.EndBeat + round(GetMidBeat(DEFAULT_FADE_OUT_TIME));
+ end;
+
+ //calculate fade time
+
+ self.Medley.FadeIn_time := GetTimeFromBeat(CurrentSong.Medley.StartBeat) -
+ GetTimeFromBeat(CurrentSong.Medley.FadeIn);
+ self.Medley.FadeOut_time := GetTimeFromBeat(CurrentSong.Medley.FadeOut) -
+ GetTimeFromBeat(CurrentSong.Medley.EndBeat);
+ end;
end;
end.
diff --git a/Medley/src/base/USongs.pas b/Medley/src/base/USongs.pas
index baeec13a..af7f7a16 100644
--- a/Medley/src/base/USongs.pas
+++ b/Medley/src/base/USongs.pas
@@ -312,18 +312,33 @@ var
Files: TPathDynArray;
Song: TSong;
Extension: IPath;
+ MedleyFiles: TPathDynArray;
+ MedleyExtension: IPath;
begin
SetLength(Files, 0);
+
Extension := Path('.txt');
+ MedleyExtension := Path('.txtm');
FindFilesByExtension(Dir, Extension, true, Files);
+
for I := 0 to High(Files) do
begin
Song := TSong.Create(Files[I]);
if Song.Analyse then
- SongList.Add(Song)
- else
+ begin
+ //medley support... TODO: move it (see USong...)
+ SetLength(MedleyFiles, 0);
+ FindFilesByExtension(Files[I].GetPath, MedleyExtension, true, MedleyFiles);
+
+ if Length(MedleyFiles)>0 then
+ begin
+ Song.ReadMedleyFile(MedleyFiles[0]);
+ end;
+
+ SongList.Add(Song);
+ end else
begin
Log.LogError('AnalyseFile failed for "' + Files[I].ToNative + '".');
FreeAndNil(Song);
diff --git a/Medley/src/base/UThemes.pas b/Medley/src/base/UThemes.pas
index 4322815e..6ffeb3b1 100644
--- a/Medley/src/base/UThemes.pas
+++ b/Medley/src/base/UThemes.pas
@@ -306,6 +306,9 @@ type
end;
TThemeSing = class(TThemeBasic)
+ //Show actual SongName
+ StaticSongName : TThemeStatic;
+ TextSongName : TThemeText;
//TimeBar mod
StaticTimeProgress: TThemeStatic;
@@ -358,7 +361,7 @@ type
LineBonusText: array [0..8] of UTF8String;
//Pause Popup
- PausePopUp: TThemeStatic;
+ PausePopUp: TThemeStatic;
end;
TThemeLyricBar = record
@@ -1051,10 +1054,13 @@ begin
// Sing
ThemeLoadBasic(Sing, 'Sing');
- //TimeBar mod
- ThemeLoadStatic(Sing.StaticTimeProgress, 'SingTimeProgress');
- ThemeLoadText(Sing.TextTimeText, 'SingTimeText');
- //eoa TimeBar mod
+ ThemeLoadStatic(Sing.StaticSongName, 'SingSongNameStatic');
+ ThemeLoadText(Sing.TextSongName, 'SingSongNameText');
+
+ //TimeBar mod
+ ThemeLoadStatic(Sing.StaticTimeProgress, 'SingTimeProgress');
+ ThemeLoadText(Sing.TextTimeText, 'SingTimeText');
+ //eoa TimeBar mod
//moveable singbar mod
ThemeLoadStatic(Sing.StaticP1SingBar, 'SingP1SingBar');