aboutsummaryrefslogtreecommitdiffstats
path: root/us_maker_edition/src
diff options
context:
space:
mode:
Diffstat (limited to 'us_maker_edition/src')
-rw-r--r--us_maker_edition/src/base/UConfig.pas2
-rw-r--r--us_maker_edition/src/base/UDraw.pas3
-rw-r--r--us_maker_edition/src/base/UEditorLyrics.pas1
-rw-r--r--us_maker_edition/src/base/UFiles.pas4
-rw-r--r--us_maker_edition/src/base/UIni.pas77
-rw-r--r--us_maker_edition/src/base/UMain.pas49
-rw-r--r--us_maker_edition/src/base/UMusic.pas75
-rw-r--r--us_maker_edition/src/base/UNote.pas62
-rw-r--r--us_maker_edition/src/base/UPathUtils.pas5
-rw-r--r--us_maker_edition/src/base/UPlatform.pas1
-rw-r--r--us_maker_edition/src/base/UPlatformMacOSX.pas34
-rw-r--r--us_maker_edition/src/base/URecord.pas120
-rw-r--r--us_maker_edition/src/base/USong.pas34
-rw-r--r--us_maker_edition/src/config-darwin.inc5
-rw-r--r--us_maker_edition/src/config-win.inc14
-rw-r--r--us_maker_edition/src/config.inc.in5
-rw-r--r--us_maker_edition/src/lib/ffmpeg/avcodec.pas59
-rw-r--r--us_maker_edition/src/lib/ffmpeg/avformat.pas18
-rw-r--r--us_maker_edition/src/lib/ffmpeg/avio.pas10
-rw-r--r--us_maker_edition/src/lib/ffmpeg/avutil.pas138
-rw-r--r--us_maker_edition/src/lib/ffmpeg/error.pas113
-rw-r--r--us_maker_edition/src/lib/ffmpeg/mathematics.pas10
-rw-r--r--us_maker_edition/src/lib/ffmpeg/opt.pas6
-rw-r--r--us_maker_edition/src/lib/ffmpeg/rational.pas10
-rw-r--r--us_maker_edition/src/lib/ffmpeg/swscale.pas10
-rw-r--r--us_maker_edition/src/lib/pcre/pcre.pas17
-rw-r--r--us_maker_edition/src/media/UAudioDecoder_FFmpeg.pas551
-rw-r--r--us_maker_edition/src/media/UAudioInput_Bass.pas7
-rw-r--r--us_maker_edition/src/media/UMediaCore_FFmpeg.pas75
-rw-r--r--us_maker_edition/src/media/UMedia_dummy.pas126
-rw-r--r--us_maker_edition/src/media/UVideo.pas521
-rw-r--r--us_maker_edition/src/media/UVisualizer.pas129
-rw-r--r--us_maker_edition/src/menu/UDisplay.pas83
-rw-r--r--us_maker_edition/src/menu/UMenuBackgroundVideo.pas6
-rw-r--r--us_maker_edition/src/screens/UScreenEditSub.pas167
-rw-r--r--us_maker_edition/src/screens/UScreenOptionsRecord.pas32
-rw-r--r--us_maker_edition/src/screens/UScreenOptionsThemes.pas8
-rw-r--r--us_maker_edition/src/screens/UScreenSing.pas134
-rw-r--r--us_maker_edition/src/screens/UScreenSong.pas131
39 files changed, 1980 insertions, 872 deletions
diff --git a/us_maker_edition/src/base/UConfig.pas b/us_maker_edition/src/base/UConfig.pas
index ef08827b..74415f4d 100644
--- a/us_maker_edition/src/base/UConfig.pas
+++ b/us_maker_edition/src/base/UConfig.pas
@@ -130,7 +130,7 @@ const
USDX_VERSION_MAJOR = 1;
USDX_VERSION_MINOR = 1;
USDX_VERSION_RELEASE = 0;
- USDX_VERSION_STATE = 'Beta';
+ USDX_VERSION_STATE = 'RC';
USDX_STRING = 'UltraStar Deluxe';
(*
diff --git a/us_maker_edition/src/base/UDraw.pas b/us_maker_edition/src/base/UDraw.pas
index bb9f28ca..77e0940d 100644
--- a/us_maker_edition/src/base/UDraw.pas
+++ b/us_maker_edition/src/base/UDraw.pas
@@ -1145,6 +1145,9 @@ begin
(LyricsState.TotalTime > 0) then
begin
LyricsProgress := CurLyricsTime / LyricsState.TotalTime;
+ // avoid that the bar "overflows" for inaccurate song lengths
+ if (LyricsProgress > 1.0) then
+ LyricsProgress := 1.0;
glTexCoord2f((width * LyricsProgress) / 8, 0);
glVertex2f(x + width * LyricsProgress, y);
diff --git a/us_maker_edition/src/base/UEditorLyrics.pas b/us_maker_edition/src/base/UEditorLyrics.pas
index 0eacd1f9..5030eff5 100644
--- a/us_maker_edition/src/base/UEditorLyrics.pas
+++ b/us_maker_edition/src/base/UEditorLyrics.pas
@@ -195,6 +195,7 @@ begin
Word[WordNum].FontStyle := FontStyleI;
SetFontStyle(FontStyleI);
SetFontSize(SizeR);
+ SetFontItalic(Italic);
Word[WordNum].Width := glTextWidth(Text);
Word[WordNum].Text := Text;
Word[WordNum].ColR := ColR;
diff --git a/us_maker_edition/src/base/UFiles.pas b/us_maker_edition/src/base/UFiles.pas
index 5a258e3e..1a7ca8f8 100644
--- a/us_maker_edition/src/base/UFiles.pas
+++ b/us_maker_edition/src/base/UFiles.pas
@@ -131,7 +131,9 @@ begin
if (Song.Encoding = encUTF8) then
SongFile.WriteString(UTF8_BOM);
- SongFile.WriteLine('#ENCODING:' + EncodingName(Song.Encoding));
+ // do not save "auto" encoding tag
+ if (Song.Encoding <> encAuto) then
+ SongFile.WriteLine('#ENCODING:' + EncodingName(Song.Encoding));
SongFile.WriteLine('#TITLE:' + EncodeToken(Song.Title));
SongFile.WriteLine('#ARTIST:' + EncodeToken(Song.Artist));
diff --git a/us_maker_edition/src/base/UIni.pas b/us_maker_edition/src/base/UIni.pas
index a4c85a3b..b198f22c 100644
--- a/us_maker_edition/src/base/UIni.pas
+++ b/us_maker_edition/src/base/UIni.pas
@@ -44,31 +44,34 @@ uses
UPath;
type
- // TInputDeviceConfig stores the configuration for an input device.
- // Configurations will be stored in the InputDeviceConfig array.
- // Note that not all devices listed in InputDeviceConfig are active devices.
- // Some might be unplugged and hence unavailable.
- // Available devices are held in TAudioInputProcessor.DeviceList. Each
- // TAudioInputDevice listed there has a CfgIndex field which is the index to
- // its configuration in the InputDeviceConfig array.
- // Name:
- // the name of the input device
- // Input:
- // the index of the input source to use for recording
- // ChannelToPlayerMap:
- // mapping of recording channels to players, e.g. ChannelToPlayerMap[0] = 2
- // maps the channel 0 (left) to player 2. A player index of 0 means that
- // the channel is not assigned to a player.
+ {**
+ * TInputDeviceConfig stores the configuration for an input device.
+ * Configurations will be stored in the InputDeviceConfig array.
+ * Note that not all devices listed in InputDeviceConfig are active devices.
+ * Some might be unplugged and hence unavailable.
+ * Available devices are held in TAudioInputProcessor.DeviceList. Each
+ * TAudioInputDevice listed there has a CfgIndex field which is the index to
+ * its configuration in the InputDeviceConfig array.
+ *}
PInputDeviceConfig = ^TInputDeviceConfig;
TInputDeviceConfig = record
- Name: string;
- Input: integer;
- Latency: integer; //**< latency in ms, or LATENCY_AUTODETECT for default
+ Name: string; //**< Name of the input device
+ Input: integer; //**< Index of the input source to use for recording
+ Latency: integer; //**< Latency in ms, or LATENCY_AUTODETECT for default
+
+ {**
+ * Mapping of recording channels to players, e.g. ChannelToPlayerMap[0] = 2
+ * maps the channel 0 (left) to player 2.
+ * A player index of 0 (CHANNEL_OFF) means that the channel is not assigned
+ * to any player (the channel is off).
+ *}
ChannelToPlayerMap: array of integer;
end;
+{* Constants for TInputDeviceConfig *}
const
- LATENCY_AUTODETECT = -1;
+ CHANNEL_OFF = 0; // for field ChannelToPlayerMap
+ LATENCY_AUTODETECT = -1; // for field Latency
type
@@ -87,6 +90,7 @@ type
procedure LoadInputDeviceCfg(IniFile: TMemIniFile);
procedure SaveInputDeviceCfg(IniFile: TIniFile);
procedure LoadThemes(IniFile: TCustomIniFile);
+
procedure LoadPaths(IniFile: TCustomIniFile);
procedure LoadScreenModes(IniFile: TCustomIniFile);
@@ -121,6 +125,8 @@ type
Spectrum: integer;
Spectrograph: integer;
MovieSize: integer;
+ VideoPreview: integer;
+ VideoEnabled: integer;
// Sound
MicBoost: integer;
@@ -164,6 +170,9 @@ type
Joypad: integer;
Mouse: integer;
+ // default encoding for texts (lyrics, song-name, ...)
+ DefaultEncoding: TEncoding;
+
procedure Load();
procedure Save();
procedure SaveNames;
@@ -214,6 +223,8 @@ const
ISpectrum: array[0..1] of UTF8String = ('Off', 'On');
ISpectrograph: array[0..1] of UTF8String = ('Off', 'On');
IMovieSize: array[0..2] of UTF8String = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
+ IVideoPreview: array[0..1] of UTF8String = ('Off', 'On');
+ IVideoEnabled: array[0..1] of UTF8String = ('Off', 'On');
IClickAssist: array[0..1] of UTF8String = ('Off', 'On');
IBeatClick: array[0..1] of UTF8String = ('Off', 'On');
@@ -295,6 +306,8 @@ var
ISpectrumTranslated: array[0..1] of UTF8String = ('Off', 'On');
ISpectrographTranslated: array[0..1] of UTF8String = ('Off', 'On');
IMovieSizeTranslated: array[0..2] of UTF8String = ('Half', 'Full [Vid]', 'Full [BG+Vid]');
+ IVideoPreviewTranslated: array[0..1] of UTF8String = ('Off', 'On');
+ IVideoEnabledTranslated: array[0..1] of UTF8String = ('Off', 'On');
IClickAssistTranslated: array[0..1] of UTF8String = ('Off', 'On');
IBeatClickTranslated: array[0..1] of UTF8String = ('Off', 'On');
@@ -415,6 +428,12 @@ begin
IMovieSizeTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_FULL_VID');
IMovieSizeTranslated[2] := ULanguage.Language.Translate('OPTION_VALUE_FULL_VID_BG');
+ IVideoPreviewTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
+ IVideoPreviewTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_ON');
+
+ IVideoEnabledTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
+ IVideoEnabledTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_ON');
+
IClickAssistTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
IClickAssistTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_ON');
@@ -658,7 +677,7 @@ begin
for ChannelIndex := 0 to High(DeviceCfg.ChannelToPlayerMap) do
begin
DeviceCfg.ChannelToPlayerMap[ChannelIndex] :=
- IniFile.ReadInteger('Record', Format('Channel%d[%d]', [ChannelIndex+1, DeviceIndex]), 0);
+ IniFile.ReadInteger('Record', Format('Channel%d[%d]', [ChannelIndex+1, DeviceIndex]), CHANNEL_OFF);
end;
end;
end;
@@ -930,6 +949,12 @@ begin
// MovieSize
MovieSize := GetArrayIndex(IMovieSize, IniFile.ReadString('Graphics', 'MovieSize', IMovieSize[2]));
+ // VideoPreview
+ VideoPreview := GetArrayIndex(IVideoPreview, IniFile.ReadString('Graphics', 'VideoPreview', IVideoPreview[1]));
+
+ // VideoEnabled
+ VideoEnabled := GetArrayIndex(IVideoEnabled, IniFile.ReadString('Graphics', 'VideoEnabled', IVideoEnabled[1]));
+
// ClickAssist
ClickAssist := GetArrayIndex(IClickAssist, IniFile.ReadString('Sound', 'ClickAssist', 'Off'));
@@ -960,6 +985,9 @@ begin
// NoteLines
NoteLines := GetArrayIndex(INoteLines, IniFile.ReadString('Lyrics', 'NoteLines', INoteLines[1]));
+ // DefaultEncoding
+ DefaultEncoding := ParseEncoding(IniFile.ReadString('Lyrics', 'Encoding', ''), encAuto);
+
LoadThemes(IniFile);
LoadInputDeviceCfg(IniFile);
@@ -1077,6 +1105,12 @@ begin
// Movie Size
IniFile.WriteString('Graphics', 'MovieSize', IMovieSize[MovieSize]);
+ // VideoPreview
+ IniFile.WriteString('Graphics', 'VideoPreview', IVideoPreview[VideoPreview]);
+
+ // VideoEnabled
+ IniFile.WriteString('Graphics', 'VideoEnabled', IVideoEnabled[VideoEnabled]);
+
// ClickAssist
IniFile.WriteString('Sound', 'ClickAssist', IClickAssist[ClickAssist]);
@@ -1110,6 +1144,9 @@ begin
// NoteLines
IniFile.WriteString('Lyrics', 'NoteLines', INoteLines[NoteLines]);
+ //Encoding default
+ IniFile.WriteString('Lyrics', 'Encoding', EncodingName(DefaultEncoding));
+
// Theme
IniFile.WriteString('Themes', 'Theme', ITheme[Theme]);
diff --git a/us_maker_edition/src/base/UMain.pas b/us_maker_edition/src/base/UMain.pas
index 0d479420..174ef162 100644
--- a/us_maker_edition/src/base/UMain.pas
+++ b/us_maker_edition/src/base/UMain.pas
@@ -39,7 +39,7 @@ uses
procedure Main;
procedure MainLoop;
-function CheckEvents: boolean;
+procedure CheckEvents;
type
TMainThreadExecProc = procedure(Data: Pointer);
@@ -98,6 +98,7 @@ uses
procedure Main;
var
WindowTitle: string;
+ BadPlayer: integer;
begin
{$IFNDEF Debug}
try
@@ -304,8 +305,14 @@ begin
SoundLib.StartBgMusic;
// check microphone settings, goto record options if they are corrupt
- if (not AudioInputProcessor.ValidateSettings) then
+ BadPlayer := AudioInputProcessor.ValidateSettings;
+ if (BadPlayer <> 0) then
+ begin
+ ScreenPopupError.ShowPopup(
+ Format(Language.Translate('ERROR_PLAYER_DEVICE_ASSIGNMENT'),
+ [BadPlayer]));
Display.CurrentScreen^.FadeTo( @ScreenOptionsRecord );
+ end;
//------------------------------
// Start Mainloop
@@ -347,13 +354,14 @@ var
Delay: integer;
TicksCurrent: cardinal;
TicksBeforeFrame: cardinal;
- Continue: boolean;
+ Done: boolean;
begin
SDL_EnableKeyRepeat(125, 125);
+ Done := false;
+
CountSkipTime(); // JB - for some reason this seems to be needed when we use the SDL Timer functions.
- while Continue do
- begin
+ repeat
TicksBeforeFrame := SDL_GetTicks;
// joypad
@@ -361,10 +369,10 @@ begin
Joy.Update;
// keyboard events
- Continue := CheckEvents;
+ CheckEvents;
// display
- Continue := Display.Draw;
+ Done := not Display.Draw;
SwapBuffers;
// FPS limiter
@@ -376,7 +384,7 @@ begin
CountSkipTime;
- end;
+ until Done;
end;
procedure DoQuit;
@@ -394,13 +402,14 @@ begin
end;
end;
-function CheckEvents: boolean;
+procedure CheckEvents;
var
Event: TSDL_event;
mouseDown: boolean;
mouseBtn: integer;
+ KeepGoing: boolean;
begin
- Result := true;
+ KeepGoing := true;
while (SDL_PollEvent(@Event) <> 0) do
begin
case Event.type_ of
@@ -445,17 +454,17 @@ begin
if not Assigned(Display.NextScreen) then
begin //drop input when changing screens
if (ScreenPopupError <> nil) and (ScreenPopupError.Visible) then
- Result := ScreenPopupError.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
+ KeepGoing := ScreenPopupError.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
else if (ScreenPopupInfo <> nil) and (ScreenPopupInfo.Visible) then
- Result := ScreenPopupInfo.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
+ KeepGoing := ScreenPopupInfo.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then
- Result := ScreenPopupCheck.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
+ KeepGoing := ScreenPopupCheck.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y)
else
begin
- Result := Display.CurrentScreen^.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y);
+ KeepGoing := Display.CurrentScreen^.ParseMouse(mouseBtn, mouseDown, Event.button.x, Event.button.y);
// if screen wants to exit
- if not Result then
+ if not KeepGoing then
DoQuit;
end;
end;
@@ -535,18 +544,18 @@ begin
// if there is a visible popup then let it handle input instead of underlying screen
// shoud be done in a way to be sure the topmost popup has preference (maybe error, then check)
else if (ScreenPopupError <> nil) and (ScreenPopupError.Visible) then
- Result := ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
+ KeepGoing := ScreenPopupError.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
else if (ScreenPopupInfo <> nil) and (ScreenPopupInfo.Visible) then
- Result := ScreenPopupInfo.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
+ KeepGoing := ScreenPopupInfo.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
else if (ScreenPopupCheck <> nil) and (ScreenPopupCheck.Visible) then
- Result := ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
+ KeepGoing := ScreenPopupCheck.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true)
else
begin
// check if screen wants to exit
- Result := Display.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true);
+ KeepGoing := Display.ParseInput(Event.key.keysym.sym, Event.key.keysym.unicode, true);
// if screen wants to exit
- if not Result then
+ if not KeepGoing then
DoQuit;
end;
diff --git a/us_maker_edition/src/base/UMusic.pas b/us_maker_edition/src/base/UMusic.pas
index 7f2b3e30..41d6e80c 100644
--- a/us_maker_edition/src/base/UMusic.pas
+++ b/us_maker_edition/src/base/UMusic.pas
@@ -43,6 +43,27 @@ uses
type
TNoteType = (ntFreestyle, ntNormal, ntGolden);
+ {**
+ * acoStretch: Stretch to screen width and height
+ * - ignores aspect
+ * + no borders
+ * + no image data loss
+ * acoCrop: Stretch to screen width or height, crop the other dimension
+ * + keeps aspect
+ * + no borders
+ * - frame borders are cropped (image data loss)
+ * acoLetterBox: Stretch to screen width, add bars at or crop top and bottom
+ * + keeps aspect
+ * - borders at top and bottom
+ * o top/bottom is cropped if width < height (unusual)
+ *}
+ TAspectCorrection = (acoStretch, acoCrop, acoLetterBox);
+
+ TRectCoords = record
+ Left, Right: double;
+ Upper, Lower: double;
+ end;
+
const
// ScoreFactor defines how a notehit of a specified notetype is
// measured in comparison to the other types
@@ -334,9 +355,49 @@ type
procedure SetPosition(Time: real);
function GetPosition: real;
- procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
+ procedure SetScreen(Screen: integer);
+ function GetScreen(): integer;
+
+ procedure SetScreenPosition(X, Y: double; Z: double = 0.0);
+ procedure GetScreenPosition(var X, Y, Z: double);
+
+ procedure SetWidth(Width: double);
+ function GetWidth(): double;
+
+ procedure SetHeight(Height: double);
+ function GetHeight(): double;
+
+ {**
+ * Sub-image of the video frame to draw.
+ * This can be used for zooming or similar purposes.
+ *}
+ procedure SetFrameRange(Range: TRectCoords);
+ function GetFrameRange(): TRectCoords;
+
+ function GetFrameAspect(): real;
+
+ procedure SetAspectCorrection(AspectCorrection: TAspectCorrection);
+ function GetAspectCorrection(): TAspectCorrection;
+
+
+ procedure SetAlpha(Alpha: double);
+ function GetAlpha(): double;
+
+ procedure SetReflectionSpacing(Spacing: double);
+ function GetReflectionSpacing(): double;
+ procedure GetFrame(Time: Extended);
+ procedure Draw();
+ procedure DrawReflection();
+
+
+ property Screen: integer read GetScreen;
+ property Width: double read GetWidth write SetWidth;
+ property Height: double read GetHeight write SetHeight;
+ property Alpha: double read GetAlpha write SetAlpha;
+ property ReflectionSpacing: double read GetReflectionSpacing write SetReflectionSpacing;
+ property FrameAspect: real read GetFrameAspect;
+ property AspectCorrection: TAspectCorrection read GetAspectCorrection write SetAspectCorrection;
property Loop: boolean read GetLoop write SetLoop;
property Position: real read GetPosition write SetPosition;
end;
@@ -414,7 +475,15 @@ type
(*
IVideoDecoder = Interface( IGenericDecoder )
['{2F184B2B-FE69-44D5-9031-0A2462391DCA}']
- function Open(const Filename: IPath): TVideoDecodeStream;
+ function Open(const Filename: IPath): TVideoDecodeStream;
+
+ procedure SetPosition(Time: real);
+ function GetPosition: real;
+
+ procedure UpdateTexture(Texture: glUint);
+
+ property Loop: boolean read GetLoop write SetLoop;
+ property Position: real read GetPosition write SetPosition;
end;
*)
diff --git a/us_maker_edition/src/base/UNote.pas b/us_maker_edition/src/base/UNote.pas
index 6eb99df9..d800d30e 100644
--- a/us_maker_edition/src/base/UNote.pas
+++ b/us_maker_edition/src/base/UNote.pas
@@ -88,12 +88,23 @@ type
Note: array of TPlayerNote;
end;
+{* Player and music info *}
var
-
- // player and music info
- Player: array of TPlayer;
+ {**
+ * Player info and state for each player.
+ * The amount of players is given by PlayersPlay.
+ *}
+ Player: array of TPlayer;
+
+ {**
+ * Number of players or teams playing.
+ * Possible values: 1 - 6
+ *}
PlayersPlay: integer;
+ {**
+ * Selected song for singing.
+ *}
CurrentSong: TSong;
const
@@ -340,8 +351,39 @@ begin
end;
procedure NewBeatDetect(Screen: TScreenSing);
+ var
+ SentenceEnd: integer;
+ I: cardinal;
begin
NewNote(Screen);
+
+ // check for sentence end
+ // we check all lines here because a new sentence may
+ // have been started even before the old one finishes
+ // due to corrupt lien breaks
+ // checking only current line works to, but may lead to
+ // weird ratings for the song files w/ the mentioned
+ // errors
+ // To-Do Philipp : check current and last line should
+ // do it for most corrupt txt and for lines in
+ // non-corrupt txts that start immediatly after the prev.
+ // line ends
+ if (assigned(Screen)) then
+ begin
+ for I := 0 to Lines[0].High do
+ begin
+ with Lines[0].Line[I] do
+ begin
+ if (HighNote > 0) then
+ begin
+ SentenceEnd := Note[HighNote].Start + Note[HighNote].Length;
+
+ if (LyricsState.OldBeatD < SentenceEnd) and (LyricsState.CurrentBeatD >= SentenceEnd) then
+ Screen.OnSentenceEnd(I);
+ end;
+ end;
+ end;
+ end;
end;
procedure NewNote(Screen: TScreenSing);
@@ -571,20 +613,6 @@ begin
end; // for PlayerIndex
//Log.LogStatus('EndBeat', 'NewBeat');
-
- // on sentence end -> for LineBonus and display of SingBar (rating pop-up)
- if (SentenceDetected >= Low(Lines[0].Line)) and
- (SentenceDetected <= High(Lines[0].Line)) then
- begin
- Line := @Lines[0].Line[SentenceDetected];
- CurrentLineFragment := @Line.Note[Line.HighNote];
- if ((CurrentLineFragment.Start + CurrentLineFragment.Length - 1) = LyricsState.CurrentBeatD) then
- begin
- if assigned(Screen) then
- Screen.OnSentenceEnd(SentenceDetected);
- end;
- end;
-
end;
end.
diff --git a/us_maker_edition/src/base/UPathUtils.pas b/us_maker_edition/src/base/UPathUtils.pas
index c2bcdd4b..2bfcde42 100644
--- a/us_maker_edition/src/base/UPathUtils.pas
+++ b/us_maker_edition/src/base/UPathUtils.pas
@@ -185,8 +185,13 @@ begin
// Add song paths
AddSongPath(Params.SongPath);
+{$IF Defined(DARWIN)}
+ AddSongPath(Platform.GetMusicPath);
+ AddSongPath(UserPath.Append('songs'));
+{$ELSE}
AddSongPath(SharedPath.Append('songs'));
AddSongPath(UserPath.Append('songs'));
+{$IFEND}
// Add category cover paths
AddCoverPath(SharedPath.Append('covers'));
diff --git a/us_maker_edition/src/base/UPlatform.pas b/us_maker_edition/src/base/UPlatform.pas
index 11c67fa7..6d884979 100644
--- a/us_maker_edition/src/base/UPlatform.pas
+++ b/us_maker_edition/src/base/UPlatform.pas
@@ -51,6 +51,7 @@ type
procedure Halt; virtual;
function GetLogPath: IPath; virtual; abstract;
+ function GetMusicPath: IPath; virtual; abstract;
function GetGameSharedPath: IPath; virtual; abstract;
function GetGameUserPath: IPath; virtual; abstract;
end;
diff --git a/us_maker_edition/src/base/UPlatformMacOSX.pas b/us_maker_edition/src/base/UPlatformMacOSX.pas
index d55e8bea..7115a6b0 100644
--- a/us_maker_edition/src/base/UPlatformMacOSX.pas
+++ b/us_maker_edition/src/base/UPlatformMacOSX.pas
@@ -108,7 +108,10 @@ type
*}
procedure CreateUserFolders();
- function GetHomeDir(): IPath;
+ {**
+ * GetHomeDir returns the path to $HOME.
+ *}
+ function GetHomeDir: IPath;
public
{**
@@ -121,13 +124,19 @@ type
{**
* GetLogPath returns the path for log messages. Currently it is set to
- * $HOME/Library/Application Support/UltraStarDeluxe/log.
+ * $HOME/Library/Logs/UltraStar Deluxe/.
*}
function GetLogPath: IPath; override;
{**
+ * GetMusicPath returns the path for music. Currently it is set to
+ * $HOME/Music/UltraStar Deluxe/.
+ *}
+ function GetMusicPath: IPath; override;
+
+ {**
* GetGameSharedPath returns the path for shared resources. Currently it
- * is set to /Library/Application Support/UltraStarDeluxe.
+ * is also set to $HOME/Library/Application Support/UltraStarDeluxe.
* However it is not used.
*}
function GetGameSharedPath: IPath; override;
@@ -135,7 +144,7 @@ type
{**
* GetGameUserPath returns the path for user resources. Currently it is
* set to $HOME/Library/Application Support/UltraStarDeluxe.
- * This is where a user can add songs, themes, ....
+ * This is where a user can add themes, ....
*}
function GetGameUserPath: IPath; override;
end;
@@ -251,21 +260,24 @@ begin
Result := GetExecutionDir().GetParent().GetParent();
end;
-function TPlatformMacOSX.GetApplicationSupportPath: IPath;
-const
- PathName: string = 'Library/Application Support/UltraStarDeluxe';
+function TPlatformMacOSX.GetHomeDir: IPath;
begin
- Result := GetHomeDir().Append(PathName, pdAppend);
+ Result := Path(GetEnvironmentVariable('HOME'));
end;
-function TPlatformMacOSX.GetHomeDir(): IPath;
+function TPlatformMacOSX.GetApplicationSupportPath: IPath;
begin
- Result := Path(GetEnvironmentVariable('HOME'));
+ Result := GetHomeDir.Append('Library/Application Support/UltraStarDeluxe', pdAppend);
end;
function TPlatformMacOSX.GetLogPath: IPath;
begin
- Result := GetApplicationSupportPath.Append('logs');
+ Result := GetHomeDir.Append('Library/Logs/UltraStar Deluxe', pdAppend);
+end;
+
+function TPlatformMacOSX.GetMusicPath: IPath;
+begin
+ Result := GetHomeDir.Append('Music/UltraStar Deluxe', pdAppend);
end;
function TPlatformMacOSX.GetGameSharedPath: IPath;
diff --git a/us_maker_edition/src/base/URecord.pas b/us_maker_edition/src/base/URecord.pas
index c183875c..5cddcc77 100644
--- a/us_maker_edition/src/base/URecord.pas
+++ b/us_maker_edition/src/base/URecord.pas
@@ -124,6 +124,8 @@ type
procedure SetVolume(Volume: single); virtual; abstract;
end;
+ TBooleanDynArray = array of boolean;
+
TAudioInputProcessor = class
public
Sound: array of TCaptureBuffer; // sound-buffers for every player
@@ -133,9 +135,36 @@ type
destructor Destroy; override;
procedure UpdateInputDeviceConfig;
- function ValidateSettings: boolean;
- // handle microphone input
+ {**
+ * Validates the mic settings.
+ * If a player was assigned to multiple mics a popup will be displayed
+ * with the ID of the player.
+ * The return value is the player number of the first player that is not
+ * configured correctly or 0 if all players are correct.
+ *}
+ function ValidateSettings: integer;
+
+ {**
+ * Checks if players 1 to PlayerCount are configured correctly.
+ * A player is configured if a device's channel is assigned to him.
+ * For each player (up to PlayerCount) the state will be in PlayerState.
+ * If a player's state is true the player is configured, otherwise not.
+ * The return value is the player number of the first player that is not
+ * configured correctly or 0 if all players are correct.
+ * The PlayerState array is zero based (index 0 for player 1).
+ *}
+ function CheckPlayersConfig(PlayerCount: cardinal;
+ var PlayerState: TBooleanDynArray): integer; overload;
+
+ {**
+ * Same as the array version but it does not output a state for each player.
+ *}
+ function CheckPlayersConfig(PlayerCount: cardinal): integer; overload;
+
+ {**
+ * Handle microphone input
+ *}
procedure HandleMicrophoneData(Buffer: PByteArray; Size: integer;
InputDevice: TAudioInputDevice);
end;
@@ -163,8 +192,6 @@ implementation
uses
ULog,
- UGraphic,
- ULanguage,
UNote;
var
@@ -555,10 +582,10 @@ begin
channelIndex := High(deviceCfg.ChannelToPlayerMap);
// add missing channels or remove non-existing ones
SetLength(deviceCfg.ChannelToPlayerMap, device.AudioFormat.Channels);
- // initialize added channels to 0
+ // assign added channels to no player
for i := channelIndex+1 to High(deviceCfg.ChannelToPlayerMap) do
begin
- deviceCfg.ChannelToPlayerMap[i] := 0;
+ deviceCfg.ChannelToPlayerMap[i] := CHANNEL_OFF;
end;
// associate ini-index with device
@@ -587,23 +614,23 @@ begin
for channelIndex := 0 to channelCount-1 do
begin
- // set default at first start of USDX (1st device, 1st channel -> player1)
- if ((channelIndex = 0) and (device.CfgIndex = 0)) then
- deviceCfg.ChannelToPlayerMap[0] := 1
- else
- deviceCfg.ChannelToPlayerMap[channelIndex] := 0;
+ // Do not set any default on first start of USDX.
+ // Otherwise most probably the wrong device (internal sound card)
+ // will be selected.
+ // It is better to force the user to configure the mics himself.
+ deviceCfg.ChannelToPlayerMap[channelIndex] := CHANNEL_OFF;
end;
end;
end;
end;
-function TAudioInputProcessor.ValidateSettings: boolean;
+function TAudioInputProcessor.ValidateSettings: integer;
const
MAX_PLAYER_COUNT = 6; // FIXME: there should be a global variable for this
var
I, J: integer;
PlayerID: integer;
- PlayerMap: array [0 .. MAX_PLAYER_COUNT] of boolean;
+ PlayerMap: array [0 .. MAX_PLAYER_COUNT - 1] of boolean;
InputDevice: TAudioInputDevice;
InputDeviceCfg: PInputDeviceConfig;
begin
@@ -621,24 +648,73 @@ begin
begin
// get player that was mapped to the current device channel
PlayerID := InputDeviceCfg.ChannelToPlayerMap[J];
- if (PlayerID <> 0) then
+ if (PlayerID <> CHANNEL_OFF) then
begin
// check if player is already assigned to another device/channel
- if (PlayerMap[PlayerID]) then
+ if (PlayerMap[PlayerID - 1]) then
begin
- ScreenPopupError.ShowPopup(
- Format(Language.Translate('ERROR_PLAYER_DEVICE_ASSIGNMENT'),
- [PlayerID]));
- Result := false;
+ Result := PlayerID;
Exit;
end;
// mark player as assigned to a device
- PlayerMap[PlayerID] := true;
+ PlayerMap[PlayerID - 1] := true;
end;
end;
end;
- Result := true;
+ Result := 0;
+end;
+
+function TAudioInputProcessor.CheckPlayersConfig(PlayerCount: cardinal;
+ var PlayerState: TBooleanDynArray): integer;
+var
+ DeviceIndex: integer;
+ ChannelIndex: integer;
+ Device: TAudioInputDevice;
+ DeviceCfg: PInputDeviceConfig;
+ PlayerIndex: integer;
+ I: integer;
+begin
+ SetLength(PlayerState, PlayerCount);
+ // set all entries to "not configured"
+ for I := 0 to High(PlayerState) do
+ begin
+ PlayerState[I] := false;
+ end;
+
+ // check each used device
+ for DeviceIndex := 0 to High(AudioInputProcessor.DeviceList) do
+ begin
+ Device := AudioInputProcessor.DeviceList[DeviceIndex];
+ if not assigned(Device) then
+ continue;
+ DeviceCfg := @Ini.InputDeviceConfig[Device.CfgIndex];
+
+ // check if device is used
+ for ChannelIndex := 0 to High(DeviceCfg.ChannelToPlayerMap) do
+ begin
+ PlayerIndex := DeviceCfg.ChannelToPlayerMap[ChannelIndex] - 1;
+ if (PlayerIndex >= 0) and (PlayerIndex < PlayerCount) then
+ PlayerState[PlayerIndex] := true;
+ end;
+ end;
+
+ Result := 0;
+ for I := 0 to High(PlayerState) do
+ begin
+ if (PlayerState[I] = false) then
+ begin
+ Result := I + 1;
+ Break;
+ end;
+ end;
+end;
+
+function TAudioInputProcessor.CheckPlayersConfig(PlayerCount: cardinal): integer;
+var
+ PlayerState: TBooleanDynArray;
+begin
+ Result := CheckPlayersConfig(PlayerCount, PlayerState);
end;
{*
@@ -737,7 +813,7 @@ begin
// check if device is used
for ChannelIndex := 0 to High(DeviceCfg.ChannelToPlayerMap) do
begin
- Player := DeviceCfg.ChannelToPlayerMap[ChannelIndex]-1;
+ Player := DeviceCfg.ChannelToPlayerMap[ChannelIndex] - 1;
if (Player < 0) or (Player >= PlayersPlay) then
begin
Device.LinkCaptureBuffer(ChannelIndex, nil);
diff --git a/us_maker_edition/src/base/USong.pas b/us_maker_edition/src/base/USong.pas
index a441fe40..e92c5b45 100644
--- a/us_maker_edition/src/base/USong.pas
+++ b/us_maker_edition/src/base/USong.pas
@@ -179,9 +179,6 @@ uses
UMusic, //needed for Lines
UNote; //needed for Player
-const
- DEFAULT_ENCODING = encAuto;
-
constructor TSong.Create();
begin
inherited;
@@ -510,22 +507,25 @@ begin
//Check for ZeroNote
if Param2 = 0 then
+ begin
Log.LogWarn(Format('"%s" in line %d: %s',
- [FileNamePath.ToNative, FileLineNo, 'found note with length zero -> note ignored']), 'TSong.LoadSong')
+ [FileNamePath.ToNative, FileLineNo,
+ 'found note with length zero -> converted to FreeStyle']),
+ 'TSong.LoadSong');
//Log.LogError('Found zero-length note at "'+Param0+' '+IntToStr(Param1)+' '+IntToStr(Param2)+' '+IntToStr(Param3)+ParamLyric+'" -> Note ignored!')
+ Param0 := 'F';
+ end;
+
+ // add notes
+ if not Both then
+ // P1
+ ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric)
else
begin
- // add notes
- if not Both then
- // P1
- ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric)
- else
- begin
- // P1 + P2
- ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric);
- ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric);
- end;
- end; //Zeronote check
+ // P1 + P2
+ ParseNote(0, Param0, (Param1+Rel[0]) * Mult, Param2 * Mult, Param3, ParamLyric);
+ ParseNote(1, Param0, (Param1+Rel[1]) * Mult, Param2 * Mult, Param3, ParamLyric);
+ end;
end // if
else if Param0 = '-' then
@@ -1087,7 +1087,7 @@ begin
// File encoding
else if (Identifier = 'ENCODING') then
begin
- self.Encoding := ParseEncoding(Value, DEFAULT_ENCODING);
+ self.Encoding := ParseEncoding(Value, Ini.DefaultEncoding);
end
// unsupported tag
@@ -1236,7 +1236,7 @@ begin
Year := 0;
// set to default encoding
- Encoding := DEFAULT_ENCODING;
+ Encoding := Ini.DefaultEncoding;
// clear custom header tags
SetLength(CustomTags, 0);
diff --git a/us_maker_edition/src/config-darwin.inc b/us_maker_edition/src/config-darwin.inc
index 83cadbae..4c128a05 100644
--- a/us_maker_edition/src/config-darwin.inc
+++ b/us_maker_edition/src/config-darwin.inc
@@ -50,4 +50,9 @@
PORTAUDIO_VERSION_RELEASE = 0;
{$IFEND}
+{$DEFINE HaveLibPcre}
+{$IF Defined(HaveLibPcre) and Defined(IncludeConstants)}
+ LIBPCRE_LIBDIR = '/sw/lib';
+{$IFEND}
+
{$UNDEF HavePortmixer}
diff --git a/us_maker_edition/src/config-win.inc b/us_maker_edition/src/config-win.inc
index 72e00aef..843fdb0e 100644
--- a/us_maker_edition/src/config-win.inc
+++ b/us_maker_edition/src/config-win.inc
@@ -8,26 +8,26 @@
{$IF Defined(HaveFFmpeg) and Defined(IncludeConstants)}
av__codec = 'avcodec-52';
LIBAVCODEC_VERSION_MAJOR = 52;
- LIBAVCODEC_VERSION_MINOR = 45;
- LIBAVCODEC_VERSION_RELEASE = 0;
+ LIBAVCODEC_VERSION_MINOR = 67;
+ LIBAVCODEC_VERSION_RELEASE = 2;
av__format = 'avformat-52';
LIBAVFORMAT_VERSION_MAJOR = 52;
- LIBAVFORMAT_VERSION_MINOR = 46;
+ LIBAVFORMAT_VERSION_MINOR = 62;
LIBAVFORMAT_VERSION_RELEASE = 0;
av__util = 'avutil-50';
LIBAVUTIL_VERSION_MAJOR = 50;
- LIBAVUTIL_VERSION_MINOR = 7;
- LIBAVUTIL_VERSION_RELEASE = 0;
+ LIBAVUTIL_VERSION_MINOR = 15;
+ LIBAVUTIL_VERSION_RELEASE = 2;
{$IFEND}
{$DEFINE HaveSWScale}
{$IF Defined(HaveSWScale) and Defined(IncludeConstants)}
sw__scale = 'swscale-0';
LIBSWSCALE_VERSION_MAJOR = 0;
- LIBSWSCALE_VERSION_MINOR = 7;
- LIBSWSCALE_VERSION_RELEASE = 2;
+ LIBSWSCALE_VERSION_MINOR = 10;
+ LIBSWSCALE_VERSION_RELEASE = 0;
{$IFEND}
{$DEFINE HaveProjectM}
diff --git a/us_maker_edition/src/config.inc.in b/us_maker_edition/src/config.inc.in
index b5e086f4..d57c7ab4 100644
--- a/us_maker_edition/src/config.inc.in
+++ b/us_maker_edition/src/config.inc.in
@@ -50,4 +50,9 @@
PORTAUDIO_VERSION_RELEASE = @portaudio_VERSION_RELEASE@;
{$IFEND}
+{$@DEFINE_HAVE_LIBPCRE@ HaveLibPcre}
+{$IF Defined(HaveLibPcre) and Defined(IncludeConstants)}
+ LIBPCRE_LIBDIR = '@libpcre_LIBDIR@';
+{$IFEND}
+
{$@DEFINE_HAVE_PORTMIXER@ HavePortmixer}
diff --git a/us_maker_edition/src/lib/ffmpeg/avcodec.pas b/us_maker_edition/src/lib/ffmpeg/avcodec.pas
index 066910a3..a441232d 100644
--- a/us_maker_edition/src/lib/ffmpeg/avcodec.pas
+++ b/us_maker_edition/src/lib/ffmpeg/avcodec.pas
@@ -14,20 +14,16 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libavcodec/avcodec.h
* Min. version: 51.16.0, revision 6577, Sat Oct 7 15:30:46 2006 UTC
- * Max. version: 52.67.0, revision 23057, Tue May 11 18:30 2010 CET
+ * Max. version: 52.72.0, revision 23338, Sun May 30 20:55 2010 CET
*
*)
@@ -86,7 +82,7 @@ const
*)
(* Max. supported version by this header *)
LIBAVCODEC_MAX_VERSION_MAJOR = 52;
- LIBAVCODEC_MAX_VERSION_MINOR = 67;
+ LIBAVCODEC_MAX_VERSION_MINOR = 72;
LIBAVCODEC_MAX_VERSION_RELEASE = 0;
LIBAVCODEC_MAX_VERSION = (LIBAVCODEC_MAX_VERSION_MAJOR * VERSION_MAJOR) +
(LIBAVCODEC_MAX_VERSION_MINOR * VERSION_MINOR) +
@@ -307,6 +303,9 @@ type
{$IF LIBAVCODEC_VERSION >= 52062000} // >= 52.62.0
CODEC_ID_YOP,
{$IFEND}
+{$IF LIBAVCODEC_VERSION >= 52067002} // >= 52.67.2
+ CODEC_ID_VP8,
+{$IFEND}
//* various PCM "codecs" */
CODEC_ID_PCM_S16LE= $10000,
@@ -850,6 +849,14 @@ const
CODEC_CAP_SUBFRAMES = $0100;
{$IFEND}
+ {$IF LIBAVCODEC_VERSION >= 52071000} // >= 52.71.0
+ (**
+ * Codec is experimental and is thus avoided in favor of non experimental
+ * encoders
+ *)
+ CODEC_CAP_EXPERIMENTAL = $0200;
+ {$IFEND}
+
//the following defines may change, don't expect compatibility if you use them
MB_TYPE_INTRA4x4 = $001;
MB_TYPE_INTRA16x16 = $002; //FIXME h264 specific
@@ -1256,6 +1263,16 @@ type
*)
log_level_offset_offset: cint;
{$IFEND}
+
+{$IF LIBAVUTIL_VERSION >= 50015003} // 50.15.3
+ (**
+ * Offset in the structure where a pointer to the parent context for loging is stored.
+ * for example a decoder that uses eval.c could pass its AVCodecContext to eval as such
+ * parent context. And a av_log() implementation could then display the parent context
+ * can be NULL of course
+ *)
+ parent_log_context_offset: cint;
+{$IFEND}
end;
{**
@@ -3012,7 +3029,11 @@ type
*)
crf_max: cfloat;
{$IFEND}
- end;
+
+ {$IF LIBAVCODEC_VERSION >= 52067002} // >= 52.67.2
+ log_level_offset: cint;
+ {$IFEND}
+ end; {TAVCodecContext}
(**
* AVCodec.
@@ -3852,6 +3873,10 @@ function avcodec_get_edge_width(): cuint;
* Modifies width and height values so that they will result in a memory
* buffer that is acceptable for the codec if you do not use any horizontal
* padding.
+ *
+ * May only be used if a codec with CODEC_CAP_DR1 has been opened.
+ * If CODEC_FLAG_EMU_EDGE is not set, the dimensions must have been increased
+ * according to avcodec_get_edge_width() before.
*)
procedure avcodec_align_dimensions(s: PAVCodecContext; width: PCint; height: PCint);
cdecl; external av__codec;
@@ -3861,6 +3886,10 @@ procedure avcodec_align_dimensions(s: PAVCodecContext; width: PCint; height: PCi
* Modifies width and height values so that they will result in a memory
* buffer that is acceptable for the codec if you also ensure that all
* line sizes are a multiple of the respective linesize_align[i].
+ *
+ * May only be used if a codec with CODEC_CAP_DR1 has been opened.
+ * If CODEC_FLAG_EMU_EDGE is not set, the dimensions must have been increased
+ * according to avcodec_get_edge_width() before.
*)
procedure avcodec_align_dimensions2(s: PAVCodecContext; width: PCint; height: PCint;
linesize_align: PQuadIntArray);
@@ -4212,6 +4241,9 @@ function av_get_bits_per_sample_format(sample_fmt: TSampleFormat): cint;
const
AV_PARSER_PTS_NB = 4;
PARSER_FLAG_COMPLETE_FRAMES = $0001;
+{$IF LIBAVCODEC_VERSION >= 52070000} // 52.70.0
+ PARSER_FLAG_ONCE = $0002;
+{$IFEND}
type
{* frame parsing *}
@@ -4694,20 +4726,19 @@ const
{$ENDIF}
(**
- * We need the sign of of the error, because some platforms have
+ * We need the sign of the error, because some platforms have
* E* and errno already negated. The previous version failed
- * with Delphi, because it needs EINVAL defined.
+ * with Delphi, because it needed EINVAL defined.
* Warning: This code is platform dependent and assumes constants
* to be 32 bit.
* This version does the following steps:
* 1) shr 30: shifts the sign bit to bit position 2
* 2) and $00000002: sets all other bits to zero
* positive EINVAL gives 0, negative gives 2
- * 3) not: inverts all bits. This gives -1 and -3
- * 4) + 2: positive EINVAL gives 1, negative -1
+ * 3) - 1: positive EINVAL gives -1, negative 1
*)
const
- AVERROR_SIGN = not((EINVAL shr 30) and $00000002) + 2;
+ AVERROR_SIGN = (EINVAL shr 30) and $00000002 - 1;
(*
#if EINVAL > 0
diff --git a/us_maker_edition/src/lib/ffmpeg/avformat.pas b/us_maker_edition/src/lib/ffmpeg/avformat.pas
index a217263d..34142125 100644
--- a/us_maker_edition/src/lib/ffmpeg/avformat.pas
+++ b/us_maker_edition/src/lib/ffmpeg/avformat.pas
@@ -14,20 +14,16 @@
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libavformat/avformat.h
* Min. version: 50.5.0 , revision 6577, Sat Oct 7 15:30:46 2006 UTC
- * Max. version: 52.62.0, revision 23102, Thu May 13 1:15:00 2010 CET
+ * Max. version: 52.67.0, revision 23357, Sun May 30 21:30:00 2010 CET
*)
unit avformat;
@@ -85,7 +81,7 @@ const
*)
(* Max. supported version by this header *)
LIBAVFORMAT_MAX_VERSION_MAJOR = 52;
- LIBAVFORMAT_MAX_VERSION_MINOR = 62;
+ LIBAVFORMAT_MAX_VERSION_MINOR = 67;
LIBAVFORMAT_MAX_VERSION_RELEASE = 0;
LIBAVFORMAT_MAX_VERSION = (LIBAVFORMAT_MAX_VERSION_MAJOR * VERSION_MAJOR) +
(LIBAVFORMAT_MAX_VERSION_MINOR * VERSION_MINOR) +
@@ -405,6 +401,9 @@ const
AVFMT_FLAG_NOFILLIN = $0010; ///< Do not infer any values from other values, just return what is stored in the container
AVFMT_FLAG_NOPARSE = $0020; ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled
{$IFEND}
+{$IF LIBAVFORMAT_VERSION >= 52063000} // >= 52.63.0
+ AVFMT_FLAG_RTP_HINT = $0040; ///< Add RTP hinting to the output file
+{$IFEND}
// used by AVStream
MAX_REORDER_DELAY = 16;
@@ -671,6 +670,9 @@ type
AVSTREAM_PARSE_FULL, (**< full parsing and repack *)
AVSTREAM_PARSE_HEADERS, (**< Only parse headers, do not repack. *)
AVSTREAM_PARSE_TIMESTAMPS (**< full parsing and interpolation of timestamps for frames not starting on a packet boundary *)
+ {$IF LIBAVFORMAT_VERSION >= 52066000} // 52.66.0
+ , AVSTREAM_PARSE_FULL_ONCE (**< full parsing and repack of the first frame only, only implemented for H.264 currently *)
+ {$IFEND}
);
TAVIndexEntry = record
diff --git a/us_maker_edition/src/lib/ffmpeg/avio.pas b/us_maker_edition/src/lib/ffmpeg/avio.pas
index 4863ee39..0ebca5fa 100644
--- a/us_maker_edition/src/lib/ffmpeg/avio.pas
+++ b/us_maker_edition/src/lib/ffmpeg/avio.pas
@@ -15,24 +15,20 @@
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libavformat/avio.h
* unbuffered I/O operations
* @warning This file has to be considered an internal but installed
* header, so it should not be directly included in your projects.
*
* update to
- * Max. avformat version: 52.62.0, revision 23004, Tue May 11 19:29:00 2010 CET
+ * Max. avformat version: 52.67.0, revision 23357, Sun May 30 21:30:00 2010 CET
*)
unit avio;
diff --git a/us_maker_edition/src/lib/ffmpeg/avutil.pas b/us_maker_edition/src/lib/ffmpeg/avutil.pas
index 959e8fda..5387a0f1 100644
--- a/us_maker_edition/src/lib/ffmpeg/avutil.pas
+++ b/us_maker_edition/src/lib/ffmpeg/avutil.pas
@@ -14,22 +14,18 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversions of
*
* libavutil/avutil.h:
* Min. version: 49.0.1, revision 6577, Sat Oct 7 15:30:46 2006 UTC
- * Max. version: 50.15.2, revision 23059, Tue May 11 22:05:00 2010 CET
+ * Max. version: 50.16.0, revision 23255, Sun May 30 22:05:00 2010 CET
*
* libavutil/mem.h:
* revision 16590, Tue Jan 13 23:44:16 2009 UTC
@@ -96,7 +92,7 @@ const
*)
(* Max. supported version by this header *)
LIBAVUTIL_MAX_VERSION_MAJOR = 50;
- LIBAVUTIL_MAX_VERSION_MINOR = 15;
+ LIBAVUTIL_MAX_VERSION_MINOR = 16;
LIBAVUTIL_MAX_VERSION_RELEASE = 0;
LIBAVUTIL_MAX_VERSION = (LIBAVUTIL_MAX_VERSION_MAJOR * VERSION_MAJOR) +
(LIBAVUTIL_MAX_VERSION_MINOR * VERSION_MINOR) +
@@ -124,7 +120,7 @@ const
* Returns the LIBAVUTIL_VERSION_INT constant.
*)
function avutil_version(): cuint;
- cdecl; external av__format;
+ cdecl; external av__util;
{$IFEND}
{$IF LIBAVUTIL_VERSION >= 50004000} // >= 50.4.0
@@ -132,13 +128,13 @@ function avutil_version(): cuint;
* Returns the libavutil build-time configuration.
*)
function avutil_configuration(): PAnsiChar;
- cdecl; external av__format;
+ cdecl; external av__util;
(**
* Returns the libavutil license.
*)
function avutil_license(): PAnsiChar;
- cdecl; external av__format;
+ cdecl; external av__util;
{$IFEND}
{
@@ -158,98 +154,9 @@ type
);
}
-(* libavutil/error.h *)
+{$INCLUDE error.pas}
-{$IF LIBAVUTIL_VERSION >= 50012000} // >= 50.12.0
-
-{* error handling *}
-
-const
-{$IFDEF UNIX}
- ENOENT = ESysENOENT;
- EIO = ESysEIO;
- ENOMEM = ESysENOMEM;
- EINVAL = ESysEINVAL;
- EDOM = ESysEDOM;
- ENOSYS = ESysENOSYS;
- EILSEQ = ESysEILSEQ;
- EPIPE = ESysEPIPE;
-{$ELSE}
- ENOENT = 2;
- EIO = 5;
- ENOMEM = 12;
- EINVAL = 22;
- EPIPE = 32; // just an assumption. needs to be checked.
- EDOM = 33;
- {$IFDEF MSWINDOWS}
- // Note: we assume that ffmpeg was compiled with MinGW.
- // This must be changed if DLLs were compiled with cygwin.
- ENOSYS = 40; // MSVC/MINGW: 40, CYGWIN: 88, LINUX/FPC: 38
- EILSEQ = 42; // MSVC/MINGW: 42, CYGWIN: 138, LINUX/FPC: 84
- {$ENDIF}
-{$ENDIF}
-
-(**
- * We need the sign of of the error, because some platforms have
- * E* and errno already negated. The previous version failed
- * with Delphi, because it needs EINVAL defined.
- * Warning: This code is platform dependent and assumes constants
- * to be 32 bit.
- * This version does the following steps:
- * 1) shr 30: shifts the sign bit to bit position 2
- * 2) and $00000002: sets all other bits to zero
- * positive EINVAL gives 0, negative gives 2
- * 3) not: inverts all bits. This gives -1 and -3
- * 4) + 2: positive EINVAL gives 1, negative -1
- *)
-const
- AVERROR_SIGN = not((EINVAL shr 30) and $00000002) + 2;
-
-(*
-#if EINVAL > 0
-#define AVERROR(e) (-(e)) {**< Returns a negative error code from a POSIX error code, to return from library functions. *}
-#define AVUNERROR(e) (-(e)) {**< Returns a POSIX error code from a library function error return value. *}
-#else
-{* Some platforms have E* and errno already negated. *}
-#define AVERROR(e) (e)
-#define AVUNERROR(e) (e)
-#endif
-*)
-
-const
- AVERROR_UNKNOWN = AVERROR_SIGN * EINVAL; (**< unknown error *)
- AVERROR_IO = AVERROR_SIGN * EIO; (**< I/O error *)
- AVERROR_NUMEXPECTED = AVERROR_SIGN * EDOM; (**< Number syntax expected in filename. *)
- AVERROR_INVALIDDATA = AVERROR_SIGN * EINVAL; (**< invalid data found *)
- AVERROR_NOMEM = AVERROR_SIGN * ENOMEM; (**< not enough memory *)
- AVERROR_NOFMT = AVERROR_SIGN * EILSEQ; (**< unknown format *)
- AVERROR_NOTSUPP = AVERROR_SIGN * ENOSYS; (**< Operation not supported. *)
- AVERROR_NOENT = AVERROR_SIGN * ENOENT; (**< No such file or directory. *)
-{$IF LIBAVCODEC_VERSION >= 52017000} // 52.17.0
- AVERROR_EOF = AVERROR_SIGN * EPIPE; (**< End of file. *)
-{$IFEND}
- // Note: function calls as constant-initializers are invalid
- //AVERROR_PATCHWELCOME = -MKTAG('P','A','W','E'); {**< Not yet implemented in FFmpeg. Patches welcome. *}
- AVERROR_PATCHWELCOME = -(ord('P') or (ord('A') shl 8) or (ord('W') shl 16) or (ord('E') shl 24));
-{$IFEND}
-
-{$IF LIBAVUTIL_VERSION >= 50013000} // >= 50.13.0
-(*
- * Puts a description of the AVERROR code errnum in errbuf.
- * In case of failure the global variable errno is set to indicate the
- * error. Even in case of failure av_strerror() will print a generic
- * error message indicating the errnum provided to errbuf.
- *
- * @param errbuf_size the size in bytes of errbuf
- * @return 0 on success, a negative value if a description for errnum
- * cannot be found
- *)
-
-function av_strerror(errnum: cint; errbuf: Pchar; errbuf_size: cint): cint;
- cdecl; external av__util;
-{$IFEND}
-
-(* libavutil/pixfmt.h *)
+(* libavutil/pixfmt.h up to revision 23144, May 16 2010 *)
type
(**
@@ -298,8 +205,8 @@ type
PIX_FMT_RGB555, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in CPU endianness, most significant bit to 0
{$IFEND}
PIX_FMT_GRAY8, ///< Y , 8bpp
- PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black
- PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white
+ PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb
+ PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb
PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette
PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG)
PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG)
@@ -316,12 +223,12 @@ type
PIX_FMT_BGR555, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in CPU endianness, most significant bit to 1
{$IFEND}
PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
- PIX_FMT_BGR4, ///< packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
+ PIX_FMT_BGR4, ///< packed RGB 1:2:1, bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits
PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
- PIX_FMT_RGB4, ///< packed RGB 1:2:1, 4bpp, (msb)1R 2G 1B(lsb)
+ PIX_FMT_RGB4, ///< packed RGB 1:2:1, bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits
PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb)
- PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
+ PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
PIX_FMT_NV21, ///< as above, but U and V bytes are swapped
{$IF LIBAVUTIL_VERSION <= 50001000} // 50.01.0
PIX_FMT_RGB32_1, ///< packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in CPU endianness
@@ -343,8 +250,8 @@ type
PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
{$IF LIBAVUTIL_VERSION >= 49015000} // 49.15.0
- PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, big-endian
- PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, little-endian
+ PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian
+ PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian
{$IFEND}
{$IF LIBAVUTIL_VERSION >= 50001000} // 50.01.0
PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
@@ -417,9 +324,10 @@ const
PIX_FMT_YUV422 = PIX_FMT_YUYV422;
{$IFEND}
-(* libavutil/common.h *) // until now MKTAG is all from common.h KMS 9/6/2009
+(* libavutil/common.h *) // until now MKTAG and MKBETAG is all from common.h KMS 19/5/2010
function MKTAG(a, b, c, d: AnsiChar): integer;
+function MKBETAG(a, b, c, d: AnsiChar): integer;
(* libavutil/mem.h *)
@@ -574,6 +482,11 @@ void av_log_set_callback(void (*)(void*, int, const char*, va_list));
void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl);
**}
+{$IF LIBAVUTIL_VERSION >= 50015003} // 50.15.3
+function av_default_item_name (ctx: pointer): Pchar;
+ cdecl; external av__util;
+{$IFEND}
+
implementation
(* libavutil/common.h *)
@@ -583,4 +496,9 @@ begin
Result := (ord(a) or (ord(b) shl 8) or (ord(c) shl 16) or (ord(d) shl 24));
end;
+function MKBETAG(a, b, c, d: AnsiChar): integer;
+begin
+ Result := (ord(d) or (ord(c) shl 8) or (ord(b) shl 16) or (ord(a) shl 24));
+end;
+
end.
diff --git a/us_maker_edition/src/lib/ffmpeg/error.pas b/us_maker_edition/src/lib/ffmpeg/error.pas
new file mode 100644
index 00000000..c142f6e1
--- /dev/null
+++ b/us_maker_edition/src/lib/ffmpeg/error.pas
@@ -0,0 +1,113 @@
+(*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This is a part of the Pascal port of ffmpeg.
+ * - Changes and updates by the UltraStar Deluxe Team
+ *
+ * Conversion of libavutil/error.h
+ * Max. avutil version: 50.16.0, revision 23255, Sun May 30 22:05:00 2010 CET
+ *
+ *)
+
+{$IF LIBAVUTIL_VERSION >= 50012000} // >= 50.12.0
+
+{* error handling *}
+
+const
+{$IFDEF UNIX}
+ ENOENT = ESysENOENT;
+ EIO = ESysEIO;
+ ENOMEM = ESysENOMEM;
+ EINVAL = ESysEINVAL;
+ EDOM = ESysEDOM;
+ ENOSYS = ESysENOSYS;
+ EILSEQ = ESysEILSEQ;
+ EPIPE = ESysEPIPE;
+{$ELSE}
+ ENOENT = 2;
+ EIO = 5;
+ ENOMEM = 12;
+ EINVAL = 22;
+ EPIPE = 32; // just an assumption. needs to be checked.
+ EDOM = 33;
+ {$IFDEF MSWINDOWS}
+ // Note: we assume that ffmpeg was compiled with MinGW.
+ // This must be changed if DLLs were compiled with cygwin.
+ ENOSYS = 40; // MSVC/MINGW: 40, CYGWIN: 88, LINUX/FPC: 38
+ EILSEQ = 42; // MSVC/MINGW: 42, CYGWIN: 138, LINUX/FPC: 84
+ {$ENDIF}
+{$ENDIF}
+
+(**
+ * We need the sign of the error, because some platforms have
+ * E* and errno already negated. The previous version failed
+ * with Delphi, because it needed EINVAL defined.
+ * Warning: This code is platform dependent and assumes constants
+ * to be 32 bit.
+ * This version does the following steps:
+ * 1) shr 30: shifts the sign bit to bit position 2
+ * 2) and $00000002: sets all other bits to zero
+ * positive EINVAL gives 0, negative gives 2
+ * 3) not: inverts all bits. This gives -1 and -3
+ * 3) - 1: positive EINVAL gives -1, negative 1
+ *)
+const
+ AVERROR_SIGN = (EINVAL shr 30) and $00000002 - 1;
+
+(*
+#if EINVAL > 0
+#define AVERROR(e) (-(e)) {**< Returns a negative error code from a POSIX error code, to return from library functions. *}
+#define AVUNERROR(e) (-(e)) {**< Returns a POSIX error code from a library function error return value. *}
+#else
+{* Some platforms have E* and errno already negated. *}
+#define AVERROR(e) (e)
+#define AVUNERROR(e) (e)
+#endif
+*)
+
+const
+ AVERROR_UNKNOWN = AVERROR_SIGN * EINVAL; (**< unknown error *)
+ AVERROR_IO = AVERROR_SIGN * EIO; (**< I/O error *)
+ AVERROR_NUMEXPECTED = AVERROR_SIGN * EDOM; (**< Number syntax expected in filename. *)
+ AVERROR_INVALIDDATA = AVERROR_SIGN * EINVAL; (**< invalid data found *)
+ AVERROR_NOMEM = AVERROR_SIGN * ENOMEM; (**< not enough memory *)
+ AVERROR_NOFMT = AVERROR_SIGN * EILSEQ; (**< unknown format *)
+ AVERROR_NOTSUPP = AVERROR_SIGN * ENOSYS; (**< Operation not supported. *)
+ AVERROR_NOENT = AVERROR_SIGN * ENOENT; (**< No such file or directory. *)
+{$IF LIBAVCODEC_VERSION >= 52017000} // 52.17.0
+ AVERROR_EOF = AVERROR_SIGN * EPIPE; (**< End of file. *)
+{$IFEND}
+ // Note: function calls as constant-initializers are invalid
+ //AVERROR_PATCHWELCOME = -MKTAG('P','A','W','E'); {**< Not yet implemented in FFmpeg. Patches welcome. *}
+ AVERROR_PATCHWELCOME = -(ord('P') or (ord('A') shl 8) or (ord('W') shl 16) or (ord('E') shl 24));
+{$IFEND}
+
+{$IF LIBAVUTIL_VERSION >= 50013000} // >= 50.13.0
+(*
+ * Puts a description of the AVERROR code errnum in errbuf.
+ * In case of failure the global variable errno is set to indicate the
+ * error. Even in case of failure av_strerror() will print a generic
+ * error message indicating the errnum provided to errbuf.
+ *
+ * @param errbuf_size the size in bytes of errbuf
+ * @return 0 on success, a negative value if a description for errnum
+ * cannot be found
+ *)
+
+function av_strerror(errnum: cint; errbuf: Pchar; errbuf_size: cint): cint;
+ cdecl; external av__util;
+{$IFEND}
diff --git a/us_maker_edition/src/lib/ffmpeg/mathematics.pas b/us_maker_edition/src/lib/ffmpeg/mathematics.pas
index 3a1f6a2c..a2a59107 100644
--- a/us_maker_edition/src/lib/ffmpeg/mathematics.pas
+++ b/us_maker_edition/src/lib/ffmpeg/mathematics.pas
@@ -14,19 +14,15 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libavutil/mathematics.h
- * avutil max. version 50.15.2, revision 23059, Tue May 11 22:10:00 2010 CET
+ * avutil max. version 50.16.0, revision 23255, Sun May 30 22:05:00 2010 CET
*
*)
diff --git a/us_maker_edition/src/lib/ffmpeg/opt.pas b/us_maker_edition/src/lib/ffmpeg/opt.pas
index c755ed35..0e73726f 100644
--- a/us_maker_edition/src/lib/ffmpeg/opt.pas
+++ b/us_maker_edition/src/lib/ffmpeg/opt.pas
@@ -15,9 +15,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
@@ -25,7 +23,7 @@
* - Changes and updates by the UltraStar Deluxe Team
*
* Conversion of libavcodec/opt.h
- * Max. avcodec version: 52.67.0, revision 23057, Tue May 11 18:17 2010 CET
+ * Max. avcodec version: 52.72.0, revision 23338, Sun May 30 20:55 2010 CET
*
*)
diff --git a/us_maker_edition/src/lib/ffmpeg/rational.pas b/us_maker_edition/src/lib/ffmpeg/rational.pas
index 6ca9c0d1..e96fccd6 100644
--- a/us_maker_edition/src/lib/ffmpeg/rational.pas
+++ b/us_maker_edition/src/lib/ffmpeg/rational.pas
@@ -15,19 +15,15 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* This is a part of Pascal porting of ffmpeg.
* - Originally by Victor Zinetz for Delphi and Free Pascal on Windows.
* - For Mac OS X, some modifications were made by The Creative CAT, denoted as CAT
* in the source codes.
* - Changes and updates by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libavutil/rational.h
- * avutil max. version 50.15.2, revision 23059, Tue May 11 22:10:00 2010 CET
+ * avutil max. version 50.16.0, revision 23255, Sun May 30 22:05:00 2010 CET
*
*)
diff --git a/us_maker_edition/src/lib/ffmpeg/swscale.pas b/us_maker_edition/src/lib/ffmpeg/swscale.pas
index 4f923f04..f7c11d0d 100644
--- a/us_maker_edition/src/lib/ffmpeg/swscale.pas
+++ b/us_maker_edition/src/lib/ffmpeg/swscale.pas
@@ -14,16 +14,12 @@
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *)
-
-(*
+ *
* FFmpeg Pascal port
* - Ported by the UltraStar Deluxe Team
- *)
-
-(*
+ *
* Conversion of libswscale/swscale.h
- * Max. version: 0.10.0, revision 31050, Tue May 11 19:40:00 2010 CET
+ * Max. version: 0.10.0, revision 31279, Tue May 30 20:25:00 2010 CET
*)
unit swscale;
diff --git a/us_maker_edition/src/lib/pcre/pcre.pas b/us_maker_edition/src/lib/pcre/pcre.pas
index 50e3371a..ab04a9d0 100644
--- a/us_maker_edition/src/lib/pcre/pcre.pas
+++ b/us_maker_edition/src/lib/pcre/pcre.pas
@@ -503,6 +503,9 @@ implementation
uses
SysUtils,
+ {$IFDEF DARWIN}
+ UConfig,
+ {$ENDIF DARWIN}
{$IFDEF MSWINDOWS}
Windows;
{$ENDIF MSWINDOWS}
@@ -536,7 +539,11 @@ const
libpcremodulename = 'libpcre.so.0';
{$ENDIF LINUX}
{$IFDEF DARWIN}
- libpcremodulename = 'libpcre.dylib';
+ libpcremodulename = 'libpcre.dylib'; // this is a symlink for example to libpcre.0.0.1.dylib
+ // the system resolves the symlink
+ libpcremodulenamefromfink = LIBPCRE_LIBDIR + '/' + libpcremodulename;
+ // the install command in the Makefile resolves the symlink, when installing libpcre.dylib in the app bundle
+ libpcremodulenamefromexecutable = '@executable_path/' + libpcremodulename;
{$ENDIF DARWIN}
PCRECompileExportName = 'pcre_compile';
PCRECompile2ExportName = 'pcre_compile2';
@@ -780,6 +787,14 @@ begin
{$IFDEF UNIX}
PCRELib := dlopen(PAnsiChar(libpcremodulename), RTLD_NOW);
{$ENDIF UNIX}
+
+ {$IFDEF DARWIN} // if libpcre.dylib is not found, first try from the executable path and finally from the fink path
+ if PCRELib = INVALID_MODULEHANDLE_VALUE then
+ PCRELib := dlopen(PAnsiChar(libpcremodulenamefromexecutable), RTLD_NOW);
+ if PCRELib = INVALID_MODULEHANDLE_VALUE then
+ PCRELib := dlopen(PAnsiChar(libpcremodulenamefromfink), RTLD_NOW);
+ {$ENDIF DARWIN}
+
Result := PCRELib <> INVALID_MODULEHANDLE_VALUE;
if Result then
begin
diff --git a/us_maker_edition/src/media/UAudioDecoder_FFmpeg.pas b/us_maker_edition/src/media/UAudioDecoder_FFmpeg.pas
index 7ca98885..c64d79c2 100644
--- a/us_maker_edition/src/media/UAudioDecoder_FFmpeg.pas
+++ b/us_maker_edition/src/media/UAudioDecoder_FFmpeg.pas
@@ -86,60 +86,60 @@ const
type
TFFmpegDecodeStream = class(TAudioDecodeStream)
private
- StateLock: PSDL_Mutex;
+ fStateLock: PSDL_Mutex;
- EOFState: boolean; // end-of-stream flag (locked by StateLock)
- ErrorState: boolean; // error flag (locked by StateLock)
+ fEOFState: boolean; // end-of-stream flag (locked by StateLock)
+ fErrorState: boolean; // error flag (locked by StateLock)
- QuitRequest: boolean; // (locked by StateLock)
- ParserIdleCond: PSDL_Cond;
+ fQuitRequest: boolean; // (locked by StateLock)
+ fParserIdleCond: PSDL_Cond;
// parser pause/resume data
- ParserLocked: boolean;
- ParserPauseRequestCount: integer;
- ParserUnlockedCond: PSDL_Cond;
- ParserResumeCond: PSDL_Cond;
-
- SeekRequest: boolean; // (locked by StateLock)
- SeekFlags: integer; // (locked by StateLock)
- SeekPos: double; // stream position to seek for (in secs) (locked by StateLock)
- SeekFlush: boolean; // true if the buffers should be flushed after seeking (locked by StateLock)
+ fParserLocked: boolean;
+ fParserPauseRequestCount: integer;
+ fParserUnlockedCond: PSDL_Cond;
+ fParserResumeCond: PSDL_Cond;
+
+ fSeekRequest: boolean; // (locked by StateLock)
+ fSeekFlags: integer; // (locked by StateLock)
+ fSeekPos: double; // stream position to seek for (in secs) (locked by StateLock)
+ fSeekFlush: boolean; // true if the buffers should be flushed after seeking (locked by StateLock)
SeekFinishedCond: PSDL_Cond;
- Loop: boolean; // (locked by StateLock)
+ fLoop: boolean; // (locked by StateLock)
- ParseThread: PSDL_Thread;
- PacketQueue: TPacketQueue;
+ fParseThread: PSDL_Thread;
+ fPacketQueue: TPacketQueue;
- FormatInfo: TAudioFormatInfo;
+ fFormatInfo: TAudioFormatInfo;
// FFmpeg specific data
- FormatCtx: PAVFormatContext;
- CodecCtx: PAVCodecContext;
- Codec: PAVCodec;
+ fFormatCtx: PAVFormatContext;
+ fCodecCtx: PAVCodecContext;
+ fCodec: PAVCodec;
- AudioStreamIndex: integer;
- AudioStream: PAVStream;
- AudioStreamPos: double; // stream position in seconds (locked by DecoderLock)
+ fAudioStreamIndex: integer;
+ fAudioStream: PAVStream;
+ fAudioStreamPos: double; // stream position in seconds (locked by DecoderLock)
// decoder pause/resume data
- DecoderLocked: boolean;
- DecoderPauseRequestCount: integer;
- DecoderUnlockedCond: PSDL_Cond;
- DecoderResumeCond: PSDL_Cond;
+ fDecoderLocked: boolean;
+ fDecoderPauseRequestCount: integer;
+ fDecoderUnlockedCond: PSDL_Cond;
+ fDecoderResumeCond: PSDL_Cond;
// state-vars for DecodeFrame (locked by DecoderLock)
- AudioPaket: TAVPacket;
- AudioPaketData: PByteArray;
- AudioPaketSize: integer;
- AudioPaketSilence: integer; // number of bytes of silence to return
+ fAudioPaket: TAVPacket;
+ fAudioPaketData: PByteArray;
+ fAudioPaketSize: integer;
+ fAudioPaketSilence: integer; // number of bytes of silence to return
// state-vars for AudioCallback (locked by DecoderLock)
- AudioBufferPos: integer;
- AudioBufferSize: integer;
- AudioBuffer: PByteArray;
+ fAudioBufferPos: integer;
+ fAudioBufferSize: integer;
+ fAudioBuffer: PByteArray;
- Filename: IPath;
+ fFilename: IPath;
procedure SetPositionIntern(Time: real; Flush: boolean; Blocking: boolean);
procedure SetEOF(State: boolean); {$IFDEF HasInline}inline;{$ENDIF}
@@ -199,13 +199,13 @@ constructor TFFmpegDecodeStream.Create();
begin
inherited Create();
- StateLock := SDL_CreateMutex();
- ParserUnlockedCond := SDL_CreateCond();
- ParserResumeCond := SDL_CreateCond();
- ParserIdleCond := SDL_CreateCond();
+ fStateLock := SDL_CreateMutex();
+ fParserUnlockedCond := SDL_CreateCond();
+ fParserResumeCond := SDL_CreateCond();
+ fParserIdleCond := SDL_CreateCond();
SeekFinishedCond := SDL_CreateCond();
- DecoderUnlockedCond := SDL_CreateCond();
- DecoderResumeCond := SDL_CreateCond();
+ fDecoderUnlockedCond := SDL_CreateCond();
+ fDecoderResumeCond := SDL_CreateCond();
// according to the documentation of avcodec_decode_audio(2), sample-data
// should be aligned on a 16 byte boundary. Otherwise internal calls
@@ -222,33 +222,33 @@ begin
// AudioBuffer was not aligned to a 16 byte boundary. The {$ALIGN x} directive
// was not applicable as Delphi in contrast to FPC provides at most 8 byte
// alignment ({$ALIGN 16} is not supported) by this directive.
- AudioBuffer := GetAlignedMem(AUDIO_BUFFER_SIZE, 16);
+ fAudioBuffer := GetAlignedMem(AUDIO_BUFFER_SIZE, 16);
Reset();
end;
procedure TFFmpegDecodeStream.Reset();
begin
- ParseThread := nil;
+ fParseThread := nil;
- EOFState := false;
- ErrorState := false;
- Loop := false;
- QuitRequest := false;
+ fEOFState := false;
+ fErrorState := false;
+ fLoop := false;
+ fQuitRequest := false;
- AudioPaketData := nil;
- AudioPaketSize := 0;
- AudioPaketSilence := 0;
+ fAudioPaketData := nil;
+ fAudioPaketSize := 0;
+ fAudioPaketSilence := 0;
- AudioBufferPos := 0;
- AudioBufferSize := 0;
+ fAudioBufferPos := 0;
+ fAudioBufferSize := 0;
- ParserLocked := false;
- ParserPauseRequestCount := 0;
- DecoderLocked := false;
- DecoderPauseRequestCount := 0;
+ fParserLocked := false;
+ fParserPauseRequestCount := 0;
+ fDecoderLocked := false;
+ fDecoderPauseRequestCount := 0;
- FillChar(AudioPaket, SizeOf(TAVPacket), 0);
+ FillChar(fAudioPaket, SizeOf(TAVPacket), 0);
end;
{*
@@ -258,15 +258,15 @@ destructor TFFmpegDecodeStream.Destroy();
begin
Close();
- SDL_DestroyMutex(StateLock);
- SDL_DestroyCond(ParserUnlockedCond);
- SDL_DestroyCond(ParserResumeCond);
- SDL_DestroyCond(ParserIdleCond);
+ SDL_DestroyMutex(fStateLock);
+ SDL_DestroyCond(fParserUnlockedCond);
+ SDL_DestroyCond(fParserResumeCond);
+ SDL_DestroyCond(fParserIdleCond);
SDL_DestroyCond(SeekFinishedCond);
- SDL_DestroyCond(DecoderUnlockedCond);
- SDL_DestroyCond(DecoderResumeCond);
+ SDL_DestroyCond(fDecoderUnlockedCond);
+ SDL_DestroyCond(fDecoderResumeCond);
- FreeAlignedMem(AudioBuffer);
+ FreeAlignedMem(fAudioBuffer);
inherited;
end;
@@ -287,20 +287,20 @@ begin
Exit;
end;
- Self.Filename := Filename;
+ Self.fFilename := Filename;
// use custom 'ufile' protocol for UTF-8 support
- if (av_open_input_file(FormatCtx, PAnsiChar('ufile:'+FileName.ToUTF8), nil, 0, nil) <> 0) then
+ if (av_open_input_file(fFormatCtx, PAnsiChar('ufile:'+FileName.ToUTF8), nil, 0, nil) <> 0) then
begin
Log.LogError('av_open_input_file failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Exit;
end;
// generate PTS values if they do not exist
- FormatCtx^.flags := FormatCtx^.flags or AVFMT_FLAG_GENPTS;
+ fFormatCtx^.flags := fFormatCtx^.flags or AVFMT_FLAG_GENPTS;
// retrieve stream information
- if (av_find_stream_info(FormatCtx) < 0) then
+ if (av_find_stream_info(fFormatCtx) < 0) then
begin
Log.LogError('av_find_stream_info failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Close();
@@ -308,14 +308,14 @@ begin
end;
// FIXME: hack used by ffplay. Maybe should not use url_feof() to test for the end
- FormatCtx^.pb.eof_reached := 0;
+ fFormatCtx^.pb.eof_reached := 0;
{$IFDEF DebugFFmpegDecode}
- dump_format(FormatCtx, 0, PAnsiChar(Filename.ToNative), 0);
+ dump_format(fFormatCtx, 0, PAnsiChar(Filename.ToNative), 0);
{$ENDIF}
- AudioStreamIndex := FFmpegCore.FindAudioStreamIndex(FormatCtx);
- if (AudioStreamIndex < 0) then
+ fAudioStreamIndex := FFmpegCore.FindAudioStreamIndex(fFormatCtx);
+ if (fAudioStreamIndex < 0) then
begin
Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename.ToNative + '"', 'UAudio_FFmpeg');
Close();
@@ -324,9 +324,9 @@ begin
//Log.LogStatus('AudioStreamIndex is: '+ inttostr(ffmpegStreamID), 'UAudio_FFmpeg');
- AudioStream := FormatCtx.streams[AudioStreamIndex];
- AudioStreamPos := 0;
- CodecCtx := AudioStream^.codec;
+ fAudioStream := fFormatCtx.streams[fAudioStreamIndex];
+ fAudioStreamPos := 0;
+ fCodecCtx := fAudioStream^.codec;
// TODO: should we use this or not? Should we allow 5.1 channel audio?
(*
@@ -338,21 +338,21 @@ begin
{$IFEND}
*)
- Codec := avcodec_find_decoder(CodecCtx^.codec_id);
- if (Codec = nil) then
+ fCodec := avcodec_find_decoder(fCodecCtx^.codec_id);
+ if (fCodec = nil) then
begin
Log.LogError('Unsupported codec!', 'UAudio_FFmpeg');
- CodecCtx := nil;
+ fCodecCtx := nil;
Close();
Exit;
end;
// set debug options
- CodecCtx^.debug_mv := 0;
- CodecCtx^.debug := 0;
+ fCodecCtx^.debug_mv := 0;
+ fCodecCtx^.debug := 0;
// detect bug-workarounds automatically
- CodecCtx^.workaround_bugs := FF_BUG_AUTODETECT;
+ fCodecCtx^.workaround_bugs := FF_BUG_AUTODETECT;
// error resilience strategy (careful/compliant/agressive/very_aggressive)
//CodecCtx^.error_resilience := FF_ER_CAREFUL; //FF_ER_COMPLIANT;
// allow non spec compliant speedup tricks.
@@ -362,7 +362,7 @@ begin
// fail if called concurrently by different threads.
FFmpegCore.LockAVCodec();
try
- AVResult := avcodec_open(CodecCtx, Codec);
+ AVResult := avcodec_open(fCodecCtx, fCodec);
finally
FFmpegCore.UnlockAVCodec();
end;
@@ -375,23 +375,23 @@ begin
// now initialize the audio-format
- if (not FFmpegCore.ConvertFFmpegToAudioFormat(CodecCtx^.sample_fmt, SampleFormat)) then
+ if (not FFmpegCore.ConvertFFmpegToAudioFormat(fCodecCtx^.sample_fmt, SampleFormat)) then
begin
// try standard format
SampleFormat := asfS16;
end;
- if CodecCtx^.channels > 255 then
+ if fCodecCtx^.channels > 255 then
Log.LogStatus('Error: CodecCtx^.channels > 255', 'TFFmpegDecodeStream.Open');
- FormatInfo := TAudioFormatInfo.Create(
- byte(CodecCtx^.channels),
- CodecCtx^.sample_rate,
+ fFormatInfo := TAudioFormatInfo.Create(
+ byte(fCodecCtx^.channels),
+ fCodecCtx^.sample_rate,
SampleFormat
);
- PacketQueue := TPacketQueue.Create();
+ fPacketQueue := TPacketQueue.Create();
// finally start the decode thread
- ParseThread := SDL_CreateThread(@ParseThreadMain, Self);
+ fParseThread := SDL_CreateThread(@ParseThreadMain, Self);
Result := true;
end;
@@ -403,47 +403,47 @@ begin
// wake threads waiting for packet-queue data
// Note: normally, there are no waiting threads. If there were waiting
// ones, they would block the audio-callback thread.
- if (assigned(PacketQueue)) then
- PacketQueue.Abort();
+ if (assigned(fPacketQueue)) then
+ fPacketQueue.Abort();
// send quit request (to parse-thread etc)
- SDL_mutexP(StateLock);
- QuitRequest := true;
- SDL_CondBroadcast(ParserIdleCond);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fQuitRequest := true;
+ SDL_CondBroadcast(fParserIdleCond);
+ SDL_mutexV(fStateLock);
// abort parse-thread
- if (ParseThread <> nil) then
+ if (fParseThread <> nil) then
begin
// and wait until it terminates
- SDL_WaitThread(ParseThread, ThreadResult);
- ParseThread := nil;
+ SDL_WaitThread(fParseThread, ThreadResult);
+ fParseThread := nil;
end;
// Close the codec
- if (CodecCtx <> nil) then
+ if (fCodecCtx <> nil) then
begin
// avcodec_close() is not thread-safe
FFmpegCore.LockAVCodec();
try
- avcodec_close(CodecCtx);
+ avcodec_close(fCodecCtx);
finally
FFmpegCore.UnlockAVCodec();
end;
- CodecCtx := nil;
+ fCodecCtx := nil;
end;
// Close the video file
- if (FormatCtx <> nil) then
+ if (fFormatCtx <> nil) then
begin
- av_close_input_file(FormatCtx);
- FormatCtx := nil;
+ av_close_input_file(fFormatCtx);
+ fFormatCtx := nil;
end;
PerformOnClose();
- FreeAndNil(PacketQueue);
- FreeAndNil(FormatInfo);
+ FreeAndNil(fPacketQueue);
+ FreeAndNil(fFormatInfo);
end;
function TFFmpegDecodeStream.GetLength(): real;
@@ -451,54 +451,54 @@ begin
// do not forget to consider the start_time value here
// there is a type size mismatch warnign because start_time and duration are cint64.
// So, in principle there could be an overflow when doing the sum.
- Result := (FormatCtx^.start_time + FormatCtx^.duration) / AV_TIME_BASE;
+ Result := (fFormatCtx^.start_time + fFormatCtx^.duration) / AV_TIME_BASE;
end;
function TFFmpegDecodeStream.GetAudioFormatInfo(): TAudioFormatInfo;
begin
- Result := FormatInfo;
+ Result := fFormatInfo;
end;
function TFFmpegDecodeStream.IsEOF(): boolean;
begin
- SDL_mutexP(StateLock);
- Result := EOFState;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Result := fEOFState;
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.SetEOF(State: boolean);
begin
- SDL_mutexP(StateLock);
- EOFState := State;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fEOFState := State;
+ SDL_mutexV(fStateLock);
end;
function TFFmpegDecodeStream.IsError(): boolean;
begin
- SDL_mutexP(StateLock);
- Result := ErrorState;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Result := fErrorState;
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.SetError(State: boolean);
begin
- SDL_mutexP(StateLock);
- ErrorState := State;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fErrorState := State;
+ SDL_mutexV(fStateLock);
end;
function TFFmpegDecodeStream.IsSeeking(): boolean;
begin
- SDL_mutexP(StateLock);
- Result := SeekRequest;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Result := fSeekRequest;
+ SDL_mutexV(fStateLock);
end;
function TFFmpegDecodeStream.IsQuit(): boolean;
begin
- SDL_mutexP(StateLock);
- Result := QuitRequest;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Result := fQuitRequest;
+ SDL_mutexV(fStateLock);
end;
function TFFmpegDecodeStream.GetPosition(): real;
@@ -509,11 +509,11 @@ begin
// ReadData() does not return all of the buffer retrieved by DecodeFrame().
// Determine the size of the unused part of the decode-buffer.
- BufferSizeSec := (AudioBufferSize - AudioBufferPos) /
- FormatInfo.BytesPerSec;
+ BufferSizeSec := (fAudioBufferSize - fAudioBufferPos) /
+ fFormatInfo.BytesPerSec;
// subtract the size of unused buffer-data from the audio clock.
- Result := AudioStreamPos - BufferSizeSec;
+ Result := fAudioStreamPos - BufferSizeSec;
ResumeDecoder();
end;
@@ -525,16 +525,16 @@ end;
function TFFmpegDecodeStream.GetLoop(): boolean;
begin
- SDL_mutexP(StateLock);
- Result := Loop;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Result := fLoop;
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.SetLoop(Enabled: boolean);
begin
- SDL_mutexP(StateLock);
- Loop := Enabled;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fLoop := Enabled;
+ SDL_mutexV(fStateLock);
end;
@@ -544,25 +544,25 @@ end;
procedure TFFmpegDecodeStream.PauseParser();
begin
- if (SDL_ThreadID() = ParseThread.threadid) then
+ if (SDL_ThreadID() = fParseThread.threadid) then
Exit;
- SDL_mutexP(StateLock);
- Inc(ParserPauseRequestCount);
- while (ParserLocked) do
- SDL_CondWait(ParserUnlockedCond, StateLock);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Inc(fParserPauseRequestCount);
+ while (fParserLocked) do
+ SDL_CondWait(fParserUnlockedCond, fStateLock);
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.ResumeParser();
begin
- if (SDL_ThreadID() = ParseThread.threadid) then
+ if (SDL_ThreadID() = fParseThread.threadid) then
Exit;
- SDL_mutexP(StateLock);
- Dec(ParserPauseRequestCount);
- SDL_CondSignal(ParserResumeCond);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Dec(fParserPauseRequestCount);
+ SDL_CondSignal(fParserResumeCond);
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.SetPositionIntern(Time: real; Flush: boolean; Blocking: boolean);
@@ -575,36 +575,36 @@ begin
// - Last lock the state lock because we are manipulating some shared state-vars.
PauseParser();
PauseDecoder();
- SDL_mutexP(StateLock);
+ SDL_mutexP(fStateLock);
try
- EOFState := false;
- ErrorState := false;
+ fEOFState := false;
+ fErrorState := false;
// do not seek if we are already at the correct position.
// This is important especially for seeking to position 0 if we already are
// at the beginning. Although seeking with AVSEEK_FLAG_BACKWARD for pos 0 works,
// it is still a bit choppy (although much better than w/o AVSEEK_FLAG_BACKWARD).
- if (Time = AudioStreamPos) then
+ if (Time = fAudioStreamPos) then
Exit;
// configure seek parameters
- SeekPos := Time;
- SeekFlush := Flush;
- SeekFlags := AVSEEK_FLAG_ANY;
- SeekRequest := true;
+ fSeekPos := Time;
+ fSeekFlush := Flush;
+ fSeekFlags := AVSEEK_FLAG_ANY;
+ fSeekRequest := true;
// Note: the BACKWARD-flag seeks to the first position <= the position
// searched for. Otherwise e.g. position 0 might not be seeked correct.
// For some reason ffmpeg sometimes doesn't use position 0 but the key-frame
// following. In streams with few key-frames (like many flv-files) the next
// key-frame after 0 might be 5secs ahead.
- if (Time <= AudioStreamPos) then
- SeekFlags := SeekFlags or AVSEEK_FLAG_BACKWARD;
+ if (Time <= fAudioStreamPos) then
+ fSeekFlags := fSeekFlags or AVSEEK_FLAG_BACKWARD;
// send a reuse signal in case the parser was stopped (e.g. because of an EOF)
- SDL_CondSignal(ParserIdleCond);
+ SDL_CondSignal(fParserIdleCond);
finally
- SDL_mutexV(StateLock);
+ SDL_mutexV(fStateLock);
ResumeDecoder();
ResumeParser();
end;
@@ -612,10 +612,10 @@ begin
// in blocking mode, wait until seeking is done
if (Blocking) then
begin
- SDL_mutexP(StateLock);
- while (SeekRequest) do
- SDL_CondWait(SeekFinishedCond, StateLock);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ while (fSeekRequest) do
+ SDL_CondWait(SeekFinishedCond, fStateLock);
+ SDL_mutexV(fStateLock);
end;
end;
@@ -635,10 +635,10 @@ begin
while (ParseLoop()) do
begin
// wait for reuse or destruction of stream
- SDL_mutexP(StateLock);
- while (not (SeekRequest or QuitRequest)) do
- SDL_CondWait(ParserIdleCond, StateLock);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ while (not (fSeekRequest or fQuitRequest)) do
+ SDL_CondWait(fParserIdleCond, fStateLock);
+ SDL_mutexV(fStateLock);
end;
end;
@@ -669,19 +669,19 @@ var
// instead and give priority to the threads requesting the parser to pause.
procedure LockParser();
begin
- SDL_mutexP(StateLock);
- while (ParserPauseRequestCount > 0) do
- SDL_CondWait(ParserResumeCond, StateLock);
- ParserLocked := true;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ while (fParserPauseRequestCount > 0) do
+ SDL_CondWait(fParserResumeCond, fStateLock);
+ fParserLocked := true;
+ SDL_mutexV(fStateLock);
end;
procedure UnlockParser();
begin
- SDL_mutexP(StateLock);
- ParserLocked := false;
- SDL_CondBroadcast(ParserUnlockedCond);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fParserLocked := false;
+ SDL_CondBroadcast(fParserUnlockedCond);
+ SDL_mutexV(fStateLock);
end;
begin
@@ -699,92 +699,92 @@ begin
end;
// handle seek-request (Note: no need to lock SeekRequest here)
- if (SeekRequest) then
+ if (fSeekRequest) then
begin
// first try: seek on the audio stream
- SeekTarget := Round(SeekPos / av_q2d(AudioStream^.time_base));
+ SeekTarget := Round(fSeekPos / av_q2d(fAudioStream^.time_base));
StartSilence := 0;
- if (SeekTarget < AudioStream^.start_time) then
- StartSilence := (AudioStream^.start_time - SeekTarget) * av_q2d(AudioStream^.time_base);
- ErrorCode := av_seek_frame(FormatCtx, AudioStreamIndex, SeekTarget, SeekFlags);
+ if (SeekTarget < fAudioStream^.start_time) then
+ StartSilence := (fAudioStream^.start_time - SeekTarget) * av_q2d(fAudioStream^.time_base);
+ ErrorCode := av_seek_frame(fFormatCtx, fAudioStreamIndex, SeekTarget, fSeekFlags);
if (ErrorCode < 0) then
begin
// second try: seek on the default stream (necessary for flv-videos and some ogg-files)
- SeekTarget := Round(SeekPos * AV_TIME_BASE);
+ SeekTarget := Round(fSeekPos * AV_TIME_BASE);
StartSilence := 0;
- if (SeekTarget < FormatCtx^.start_time) then
- StartSilence := (FormatCtx^.start_time - SeekTarget) / AV_TIME_BASE;
- ErrorCode := av_seek_frame(FormatCtx, -1, SeekTarget, SeekFlags);
+ if (SeekTarget < fFormatCtx^.start_time) then
+ StartSilence := (fFormatCtx^.start_time - SeekTarget) / AV_TIME_BASE;
+ ErrorCode := av_seek_frame(fFormatCtx, -1, SeekTarget, fSeekFlags);
end;
// pause decoder and lock state (keep the lock-order to avoid deadlocks).
// Note that the decoder does not block in the packet-queue in seeking state,
// so locking the decoder here does not cause a dead-lock.
PauseDecoder();
- SDL_mutexP(StateLock);
+ SDL_mutexP(fStateLock);
try
if (ErrorCode < 0) then
begin
// seeking failed
- ErrorState := true;
- Log.LogStatus('Seek Error in "'+FormatCtx^.filename+'"', 'UAudioDecoder_FFmpeg');
+ fErrorState := true;
+ Log.LogError('Seek Error in "'+fFormatCtx^.filename+'"', 'UAudioDecoder_FFmpeg');
end
else
begin
- if (SeekFlush) then
+ if (fSeekFlush) then
begin
// flush queue (we will send a Flush-Packet when seeking is finished)
- PacketQueue.Flush();
+ fPacketQueue.Flush();
// flush the decode buffers
- AudioBufferSize := 0;
- AudioBufferPos := 0;
- AudioPaketSize := 0;
- AudioPaketSilence := 0;
+ fAudioBufferSize := 0;
+ fAudioBufferPos := 0;
+ fAudioPaketSize := 0;
+ fAudioPaketSilence := 0;
FlushCodecBuffers();
// Set preliminary stream position. The position will be set to
// the correct value as soon as the first packet is decoded.
- AudioStreamPos := SeekPos;
+ fAudioStreamPos := fSeekPos;
end
else
begin
// request avcodec buffer flush
- PacketQueue.PutStatus(PKT_STATUS_FLAG_FLUSH, nil);
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_FLUSH, nil);
end;
// fill the gap between position 0 and start_time with silence
// but not if we are in loop mode
- if ((StartSilence > 0) and (not Loop)) then
+ if ((StartSilence > 0) and (not fLoop)) then
begin
GetMem(StartSilencePtr, SizeOf(StartSilence));
StartSilencePtr^ := StartSilence;
- PacketQueue.PutStatus(PKT_STATUS_FLAG_EMPTY, StartSilencePtr);
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_EMPTY, StartSilencePtr);
end;
end;
- SeekRequest := false;
+ fSeekRequest := false;
SDL_CondBroadcast(SeekFinishedCond);
finally
- SDL_mutexV(StateLock);
+ SDL_mutexV(fStateLock);
ResumeDecoder();
end;
end;
- if (PacketQueue.GetSize() > MAX_AUDIOQ_SIZE) then
+ if (fPacketQueue.GetSize() > MAX_AUDIOQ_SIZE) then
begin
SDL_Delay(10);
Continue;
end;
- if (av_read_frame(FormatCtx, Packet) < 0) then
+ if (av_read_frame(fFormatCtx, Packet) < 0) then
begin
// failed to read a frame, check reason
{$IF (LIBAVFORMAT_VERSION_MAJOR >= 52)}
- ByteIOCtx := FormatCtx^.pb;
+ ByteIOCtx := fFormatCtx^.pb;
{$ELSE}
- ByteIOCtx := @FormatCtx^.pb;
+ ByteIOCtx := @fFormatCtx^.pb;
{$IFEND}
// check for end-of-file (eof is not an error)
@@ -799,7 +799,7 @@ begin
else
begin
// signal end-of-file
- PacketQueue.PutStatus(PKT_STATUS_FLAG_EOF, nil);
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_EOF, nil);
Exit;
end;
end;
@@ -808,17 +808,26 @@ begin
if (url_ferror(ByteIOCtx) <> 0) then
begin
// an error occured -> abort and wait for repositioning or termination
- PacketQueue.PutStatus(PKT_STATUS_FLAG_ERROR, nil);
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_ERROR, nil);
Exit;
end;
- // no error -> wait for user input
- SDL_Delay(100);
- Continue;
+ // url_feof() does not detect an EOF for some files
+ // so we have to do it this way.
+ if ((fFormatCtx^.file_size <> 0) and
+ (ByteIOCtx^.pos >= fFormatCtx^.file_size)) then
+ begin
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_EOF, nil);
+ Exit;
+ end;
+
+ // unknown error occured, exit
+ fPacketQueue.PutStatus(PKT_STATUS_FLAG_ERROR, nil);
+ Exit;
end;
- if (Packet.stream_index = AudioStreamIndex) then
- PacketQueue.Put(@Packet)
+ if (Packet.stream_index = fAudioStreamIndex) then
+ fPacketQueue.Put(@Packet)
else
av_free_packet(@Packet);
@@ -835,28 +844,28 @@ end;
procedure TFFmpegDecodeStream.PauseDecoder();
begin
- SDL_mutexP(StateLock);
- Inc(DecoderPauseRequestCount);
- while (DecoderLocked) do
- SDL_CondWait(DecoderUnlockedCond, StateLock);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Inc(fDecoderPauseRequestCount);
+ while (fDecoderLocked) do
+ SDL_CondWait(fDecoderUnlockedCond, fStateLock);
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.ResumeDecoder();
begin
- SDL_mutexP(StateLock);
- Dec(DecoderPauseRequestCount);
- SDL_CondSignal(DecoderResumeCond);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ Dec(fDecoderPauseRequestCount);
+ SDL_CondSignal(fDecoderResumeCond);
+ SDL_mutexV(fStateLock);
end;
procedure TFFmpegDecodeStream.FlushCodecBuffers();
begin
// if no flush operation is specified, avcodec_flush_buffers will not do anything.
- if (@CodecCtx.codec.flush <> nil) then
+ if (@fCodecCtx.codec.flush <> nil) then
begin
// flush buffers used by avcodec_decode_audio, etc.
- avcodec_flush_buffers(CodecCtx);
+ avcodec_flush_buffers(fCodecCtx);
end
else
begin
@@ -865,8 +874,8 @@ begin
// We will just reopen the codec.
FFmpegCore.LockAVCodec();
try
- avcodec_close(CodecCtx);
- avcodec_open(CodecCtx, Codec);
+ avcodec_close(fCodecCtx);
+ avcodec_open(fCodecCtx, fCodec);
finally
FFmpegCore.UnlockAVCodec();
end;
@@ -892,27 +901,27 @@ begin
begin
// for titles with start_time > 0 we have to generate silence
// until we reach the pts of the first data packet.
- if (AudioPaketSilence > 0) then
+ if (fAudioPaketSilence > 0) then
begin
- DataSize := Min(AudioPaketSilence, BufferSize);
+ DataSize := Min(fAudioPaketSilence, BufferSize);
FillChar(Buffer[0], DataSize, 0);
- Dec(AudioPaketSilence, DataSize);
- AudioStreamPos := AudioStreamPos + DataSize / FormatInfo.BytesPerSec;
+ Dec(fAudioPaketSilence, DataSize);
+ fAudioStreamPos := fAudioStreamPos + DataSize / fFormatInfo.BytesPerSec;
Result := DataSize;
Exit;
end;
// read packet data
- while (AudioPaketSize > 0) do
+ while (fAudioPaketSize > 0) do
begin
DataSize := BufferSize;
{$IF LIBAVCODEC_VERSION >= 51030000} // 51.30.0
- PaketDecodedSize := avcodec_decode_audio2(CodecCtx, PSmallint(Buffer),
- DataSize, AudioPaketData, AudioPaketSize);
+ PaketDecodedSize := avcodec_decode_audio2(fCodecCtx, PSmallint(Buffer),
+ DataSize, fAudioPaketData, fAudioPaketSize);
{$ELSE}
- PaketDecodedSize := avcodec_decode_audio(CodecCtx, PSmallint(Buffer),
- DataSize, AudioPaketData, AudioPaketSize);
+ PaketDecodedSize := avcodec_decode_audio(fCodecCtx, PSmallint(Buffer),
+ DataSize, fAudioPaketData, fAudioPaketSize);
{$IFEND}
if(PaketDecodedSize < 0) then
@@ -921,19 +930,19 @@ begin
{$IFDEF DebugFFmpegDecode}
DebugWriteln('Skip audio frame');
{$ENDIF}
- AudioPaketSize := 0;
+ fAudioPaketSize := 0;
Break;
end;
- Inc(AudioPaketData, PaketDecodedSize);
- Dec(AudioPaketSize, PaketDecodedSize);
+ Inc(fAudioPaketData, PaketDecodedSize);
+ Dec(fAudioPaketSize, PaketDecodedSize);
// check if avcodec_decode_audio returned data, otherwise fetch more frames
if (DataSize <= 0) then
Continue;
// update stream position by the amount of fetched data
- AudioStreamPos := AudioStreamPos + DataSize / FormatInfo.BytesPerSec;
+ fAudioStreamPos := fAudioStreamPos + DataSize / fFormatInfo.BytesPerSec;
// we have data, return it and come back for more later
Result := DataSize;
@@ -941,8 +950,8 @@ begin
end;
// free old packet data
- if (AudioPaket.data <> nil) then
- av_free_packet(@AudioPaket);
+ if (fAudioPaket.data <> nil) then
+ av_free_packet(@fAudioPaket);
// do not block queue on seeking (to avoid deadlocks on the DecoderLock)
if (IsSeeking()) then
@@ -952,17 +961,17 @@ begin
// request a new packet and block if none available.
// If this fails, the queue was aborted.
- if (PacketQueue.Get(AudioPaket, BlockQueue) <= 0) then
+ if (fPacketQueue.Get(fAudioPaket, BlockQueue) <= 0) then
Exit;
// handle Status-packet
- if (PAnsiChar(AudioPaket.data) = STATUS_PACKET) then
+ if (PAnsiChar(fAudioPaket.data) = STATUS_PACKET) then
begin
- AudioPaket.data := nil;
- AudioPaketData := nil;
- AudioPaketSize := 0;
+ fAudioPaket.data := nil;
+ fAudioPaketData := nil;
+ fAudioPaketSize := 0;
- case (AudioPaket.flags) of
+ case (fAudioPaket.flags) of
PKT_STATUS_FLAG_FLUSH:
begin
// just used if SetPositionIntern was called without the flush flag.
@@ -984,9 +993,9 @@ begin
end;
PKT_STATUS_FLAG_EMPTY:
begin
- SilenceDuration := PDouble(PacketQueue.GetStatusInfo(AudioPaket))^;
- AudioPaketSilence := Round(SilenceDuration * FormatInfo.SampleRate) * FormatInfo.FrameSize;
- PacketQueue.FreeStatusInfo(AudioPaket);
+ SilenceDuration := PDouble(fPacketQueue.GetStatusInfo(fAudioPaket))^;
+ fAudioPaketSilence := Round(SilenceDuration * fFormatInfo.SampleRate) * fFormatInfo.FrameSize;
+ fPacketQueue.FreeStatusInfo(fAudioPaket);
end
else
begin
@@ -997,20 +1006,20 @@ begin
Continue;
end;
- AudioPaketData := AudioPaket.data;
- AudioPaketSize := AudioPaket.size;
+ fAudioPaketData := fAudioPaket.data;
+ fAudioPaketSize := fAudioPaket.size;
// if available, update the stream position to the presentation time of this package
- if(AudioPaket.pts <> AV_NOPTS_VALUE) then
+ if(fAudioPaket.pts <> AV_NOPTS_VALUE) then
begin
{$IFDEF DebugFFmpegDecode}
- TmpPos := AudioStreamPos;
+ TmpPos := fAudioStreamPos;
{$ENDIF}
- AudioStreamPos := av_q2d(AudioStream^.time_base) * AudioPaket.pts;
+ fAudioStreamPos := av_q2d(fAudioStream^.time_base) * fAudioPaket.pts;
{$IFDEF DebugFFmpegDecode}
- DebugWriteln('Timestamp: ' + floattostrf(AudioStreamPos, ffFixed, 15, 3) + ' ' +
+ DebugWriteln('Timestamp: ' + floattostrf(fAudioStreamPos, ffFixed, 15, 3) + ' ' +
'(Calc: ' + floattostrf(TmpPos, ffFixed, 15, 3) + '), ' +
- 'Diff: ' + floattostrf(AudioStreamPos-TmpPos, ffFixed, 15, 3));
+ 'Diff: ' + floattostrf(fAudioStreamPos-TmpPos, ffFixed, 15, 3));
{$ENDIF}
end;
end;
@@ -1025,19 +1034,19 @@ var
// prioritize pause requests
procedure LockDecoder();
begin
- SDL_mutexP(StateLock);
- while (DecoderPauseRequestCount > 0) do
- SDL_CondWait(DecoderResumeCond, StateLock);
- DecoderLocked := true;
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ while (fDecoderPauseRequestCount > 0) do
+ SDL_CondWait(fDecoderResumeCond, fStateLock);
+ fDecoderLocked := true;
+ SDL_mutexV(fStateLock);
end;
procedure UnlockDecoder();
begin
- SDL_mutexP(StateLock);
- DecoderLocked := false;
- SDL_CondBroadcast(DecoderUnlockedCond);
- SDL_mutexV(StateLock);
+ SDL_mutexP(fStateLock);
+ fDecoderLocked := false;
+ SDL_CondBroadcast(fDecoderUnlockedCond);
+ SDL_mutexV(fStateLock);
end;
begin
@@ -1056,15 +1065,15 @@ begin
while (BufferPos < BufferSize) do
begin
// check if we need more data
- if (AudioBufferPos >= AudioBufferSize) then
+ if (fAudioBufferPos >= fAudioBufferSize) then
begin
- AudioBufferPos := 0;
+ fAudioBufferPos := 0;
// we have already sent all our data; get more
- AudioBufferSize := DecodeFrame(AudioBuffer, AUDIO_BUFFER_SIZE);
+ fAudioBufferSize := DecodeFrame(fAudioBuffer, AUDIO_BUFFER_SIZE);
// check for errors or EOF
- if(AudioBufferSize < 0) then
+ if(fAudioBufferSize < 0) then
begin
Result := BufferPos;
Exit;
@@ -1072,16 +1081,16 @@ begin
end;
// calc number of new bytes in the decode-buffer
- CopyByteCount := AudioBufferSize - AudioBufferPos;
+ CopyByteCount := fAudioBufferSize - fAudioBufferPos;
// resize copy-count if more bytes available than needed (remaining bytes are used the next time)
RemainByteCount := BufferSize - BufferPos;
if (CopyByteCount > RemainByteCount) then
CopyByteCount := RemainByteCount;
- Move(AudioBuffer[AudioBufferPos], Buffer[BufferPos], CopyByteCount);
+ Move(fAudioBuffer[fAudioBufferPos], Buffer[BufferPos], CopyByteCount);
Inc(BufferPos, CopyByteCount);
- Inc(AudioBufferPos, CopyByteCount);
+ Inc(fAudioBufferPos, CopyByteCount);
end;
finally
UnlockDecoder();
diff --git a/us_maker_edition/src/media/UAudioInput_Bass.pas b/us_maker_edition/src/media/UAudioInput_Bass.pas
index b8f914c5..0e79b343 100644
--- a/us_maker_edition/src/media/UAudioInput_Bass.pas
+++ b/us_maker_edition/src/media/UAudioInput_Bass.pas
@@ -471,9 +471,12 @@ begin
Flags := BASS_RecordGetInput(SourceIndex, PSingle(nil)^);
if (Flags <> -1) then
begin
- // is the current source a mic-source?
- if ((Flags and BASS_INPUT_TYPE_MIC) <> 0) then
+ // chech if current source is a mic (and none was set before)
+ if ((Flags and BASS_INPUT_TYPE_MIC) <> 0) and
+ (BassDevice.MicSource = -1) then
+ begin
BassDevice.MicSource := SourceIndex;
+ end;
end;
Inc(SourceIndex);
diff --git a/us_maker_edition/src/media/UMediaCore_FFmpeg.pas b/us_maker_edition/src/media/UMediaCore_FFmpeg.pas
index 2d572ff2..eb136995 100644
--- a/us_maker_edition/src/media/UMediaCore_FFmpeg.pas
+++ b/us_maker_edition/src/media/UMediaCore_FFmpeg.pas
@@ -41,6 +41,7 @@ uses
avformat,
avutil,
avio,
+ swscale,
UMusic,
ULog,
UPath;
@@ -121,9 +122,83 @@ const
var
Instance: TMediaCore_FFmpeg;
+function AV_VERSION_INT(a, b, c: cardinal): cuint;
+begin
+ Result := (a shl 16) or (b shl 8) or c;
+end;
+
+procedure CheckVersions();
+var
+ libVersion: cuint;
+ headerVersion: cuint;
+
+ function hexVerToStr(Version: cuint): string;
+ var
+ Major, Minor, Release: cardinal;
+ begin
+ Major := (Version shr 16) and $FF;;
+ Minor := (Version shr 8) and $FF;
+ Release := Version and $FF;
+ Result := Format('%d.%d.%d', [Major, Minor, Release]);
+ end;
+
+begin
+ libVersion := avcodec_version();
+ headerVersion := AV_VERSION_INT(
+ LIBAVCODEC_VERSION_MAJOR,
+ LIBAVCODEC_VERSION_MINOR,
+ LIBAVCODEC_VERSION_RELEASE);
+ if (libVersion <> headerVersion) then
+ begin
+ Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
+ ['libavcodec', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
+ end;
+
+ {$IF LIBAVFORMAT_VERSION >= 52020000} // 52.20.0
+ libVersion := avformat_version();
+ headerVersion := AV_VERSION_INT(
+ LIBAVFORMAT_VERSION_MAJOR,
+ LIBAVFORMAT_VERSION_MINOR,
+ LIBAVFORMAT_VERSION_RELEASE);
+ if (libVersion <> headerVersion) then
+ begin
+ Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
+ ['libavformat', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
+ end;
+ {$IFEND}
+
+ {$IF LIBAVUTIL_VERSION >= 49008000} // 49.8.0
+ libVersion := avutil_version();
+ headerVersion := AV_VERSION_INT(
+ LIBAVUTIL_VERSION_MAJOR,
+ LIBAVUTIL_VERSION_MINOR,
+ LIBAVUTIL_VERSION_RELEASE);
+ if (libVersion <> headerVersion) then
+ begin
+ Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
+ ['libavutil', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
+ end;
+ {$IFEND}
+
+ {$IF LIBSWSCALE_VERSION >= 000006001} // 0.6.1
+ libVersion := swscale_version();
+ headerVersion := AV_VERSION_INT(
+ LIBSWSCALE_VERSION_MAJOR,
+ LIBSWSCALE_VERSION_MINOR,
+ LIBSWSCALE_VERSION_RELEASE);
+ if (libVersion <> headerVersion) then
+ begin
+ Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
+ ['libswscale', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
+ end;
+ {$IFEND}
+end;
+
constructor TMediaCore_FFmpeg.Create();
begin
inherited;
+
+ CheckVersions();
av_register_protocol(@UTF8FileProtocol);
AVCodecLock := SDL_CreateMutex();
end;
diff --git a/us_maker_edition/src/media/UMedia_dummy.pas b/us_maker_edition/src/media/UMedia_dummy.pas
index 8ebfd3a9..46cbe6b8 100644
--- a/us_maker_edition/src/media/UMedia_dummy.pas
+++ b/us_maker_edition/src/media/UMedia_dummy.pas
@@ -112,9 +112,43 @@ type
procedure SetPosition(Time: real);
function GetPosition: real;
- procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
+ procedure SetScreen(Screen: integer);
+ function GetScreen(): integer;
+
+ procedure SetScreenPosition(X, Y, Z: double);
+ procedure GetScreenPosition(var X, Y, Z: double);
+
+ procedure SetWidth(Width: double);
+ function GetWidth(): double;
+
+ procedure SetHeight(Height: double);
+ function GetHeight(): double;
+
+ procedure SetFrameRange(Range: TRectCoords);
+ function GetFrameRange(): TRectCoords;
+
+ function GetFrameAspect(): real;
+
+ procedure SetAspectCorrection(AspectCorrection: TAspectCorrection);
+ function GetAspectCorrection(): TAspectCorrection;
+
+ procedure SetAlpha(Alpha: double);
+ function GetAlpha(): double;
+
+ procedure SetReflectionSpacing(Spacing: double);
+ function GetReflectionSpacing(): double;
+ procedure GetFrame(Time: Extended);
+ procedure Draw();
+ procedure DrawReflection();
+
+ property Screen: integer read GetScreen;
+ property Width: double read GetWidth write SetWidth;
+ property Height: double read GetHeight write SetWidth;
+ property Alpha: double read GetAlpha write SetAlpha;
+ property ReflectionSpacing: double read GetReflectionSpacing write SetReflectionSpacing;
+ property FrameAspect: real read GetFrameAspect;
+ property AspectCorrection: TAspectCorrection read GetAspectCorrection;
property Loop: boolean read GetLoop write SetLoop;
property Position: real read GetPosition write SetPosition;
end;
@@ -329,11 +363,97 @@ begin
Result := 0;
end;
+procedure TVideo_Dummy.SetScreen(Screen: integer);
+begin
+end;
+
+function TVideo_Dummy.GetScreen(): integer;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.SetScreenPosition(X, Y, Z: double);
+begin
+end;
+
+procedure TVideo_Dummy.GetScreenPosition(var X, Y, Z: double);
+begin
+ X := 0;
+ Y := 0;
+ Z := 0;
+end;
+
+procedure TVideo_Dummy.SetWidth(Width: double);
+begin
+end;
+
+function TVideo_Dummy.GetWidth(): double;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.SetHeight(Height: double);
+begin
+end;
+
+function TVideo_Dummy.GetHeight(): double;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.SetFrameRange(Range: TRectCoords);
+begin
+end;
+
+function TVideo_Dummy.GetFrameRange(): TRectCoords;
+begin
+ Result.Left := 0;
+ Result.Right := 0;
+ Result.Upper := 0;
+ Result.Lower := 0;
+end;
+
+function TVideo_Dummy.GetFrameAspect(): real;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.SetAspectCorrection(AspectCorrection: TAspectCorrection);
+begin
+end;
+
+function TVideo_Dummy.GetAspectCorrection(): TAspectCorrection;
+begin
+ Result := acoStretch;
+end;
+
+procedure TVideo_Dummy.SetAlpha(Alpha: double);
+begin
+end;
+
+function TVideo_Dummy.GetAlpha(): double;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.SetReflectionSpacing(Spacing: double);
+begin
+end;
+
+function TVideo_Dummy.GetReflectionSpacing(): double;
+begin
+ Result := 0;
+end;
+
procedure TVideo_Dummy.GetFrame(Time: Extended);
begin
end;
-procedure TVideo_Dummy.DrawGL(Screen: integer);
+procedure TVideo_Dummy.Draw();
+begin
+end;
+
+procedure TVideo_Dummy.DrawReflection();
begin
end;
diff --git a/us_maker_edition/src/media/UVideo.pas b/us_maker_edition/src/media/UVideo.pas
index c7d59fc8..add7bdc8 100644
--- a/us_maker_edition/src/media/UVideo.pas
+++ b/us_maker_edition/src/media/UVideo.pas
@@ -48,24 +48,6 @@ interface
{$DEFINE PIXEL_FMT_BGR}
{$ENDIF}
-type
- {**
- * vacStretch: Stretch to screen width and height
- * - ignores aspect
- * + no borders
- * + no image data loss
- * vacCrop: Stretch to screen width or height, crop the other dimension
- * + keeps aspect
- * + no borders
- * - frame borders are cropped (image data loss)
- * vacLetterBox: Stretch to screen width, add bars at or crop top and bottom
- * + keeps aspect
- * - borders at top and bottom
- * o top/bottom is cropped if width < height (unusual)
- *}
- TAspectCorrection = (acoStretch, acoCrop, acoLetterBox);
-
-
implementation
uses
@@ -112,12 +94,9 @@ const
PIXEL_FMT_SIZE = 3;
{$ENDIF}
-type
- TRectCoords = record
- Left, Right: double;
- Upper, Lower: double;
- end;
+ ReflectionH = 0.5; //reflection height (50%)
+type
IVideo_FFmpeg = interface (IVideo)
['{E640E130-C8C0-4399-AF02-67A3569313AB}']
function Open(const FileName: IPath): boolean;
@@ -149,11 +128,25 @@ type
fSwScaleContext: PSwsContext;
{$ENDIF}
+ fScreen: integer; //actual screen to draw on
+
+ fPosX: double;
+ fPosY: double;
+ fPosZ: double;
+ fWidth: double;
+ fHeight: double;
+
+ fFrameRange: TRectCoords;
+
+ fAlpha: double;
+ fReflectionSpacing: double;
+
+
fAspect: real; //**< width/height ratio
fAspectCorrection: TAspectCorrection;
- fTimeBase: extended; //**< FFmpeg time base per time unit
- fFrameTime: extended; //**< video time position (absolute)
+ fFrameDuration: extended; //**< duration of a video frame in seconds (= 1/fps)
+ fFrameTime: extended; //**< video time position (absolute)
fLoopTime: extended; //**< start time of the current loop
fPboEnabled: boolean;
@@ -163,6 +156,8 @@ type
procedure SynchronizeTime(Frame: PAVFrame; var pts: double);
procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords);
+ procedure DrawBorders(ScreenRect: TRectCoords);
+ procedure DrawBordersReflected(ScreenRect: TRectCoords; AlphaUpper, AlphaLower: double);
procedure ShowDebugInfo();
@@ -183,8 +178,39 @@ type
procedure SetPosition(Time: real);
function GetPosition: real;
- procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
+ procedure SetScreen(Screen: integer);
+ function GetScreen(): integer;
+
+ procedure SetScreenPosition(X, Y, Z: double);
+ procedure GetScreenPosition(var X, Y, Z: double);
+
+ procedure SetWidth(Width: double);
+ function GetWidth(): double;
+
+ procedure SetHeight(Height: double);
+ function GetHeight(): double;
+
+ {**
+ * Sub-image of the video frame to draw.
+ * This can be used for zooming or similar purposes.
+ *}
+ procedure SetFrameRange(Range: TRectCoords);
+ function GetFrameRange(): TRectCoords;
+
+ function GetFrameAspect(): real;
+
+ procedure SetAspectCorrection(AspectCorrection: TAspectCorrection);
+ function GetAspectCorrection(): TAspectCorrection;
+
+ procedure SetAlpha(Alpha: double);
+ function GetAlpha(): double;
+
+ procedure SetReflectionSpacing(Spacing: double);
+ function GetReflectionSpacing(): double;
+
+ procedure GetFrame(Time: Extended);
+ procedure Draw();
+ procedure DrawReflection();
end;
TVideoPlayback_FFmpeg = class( TInterfacedObject, IVideoPlayback )
@@ -406,19 +432,18 @@ begin
fAspect := fAspect * fCodecContext^.width /
fCodecContext^.height;
- fTimeBase := 1/av_q2d(fStream^.r_frame_rate);
+ fFrameDuration := 1/av_q2d(fStream^.r_frame_rate);
- // hack to get reasonable timebase (for divx and others)
- if (fTimeBase < 0.02) then // 0.02 <-> 50 fps
+ // hack to get reasonable framerate (for divx and others)
+ if (fFrameDuration < 0.02) then // 0.02 <-> 50 fps
begin
- fTimeBase := av_q2d(fStream^.r_frame_rate);
- while (fTimeBase > 50) do
- fTimeBase := fTimeBase/10;
- fTimeBase := 1/fTimeBase;
+ fFrameDuration := av_q2d(fStream^.r_frame_rate);
+ while (fFrameDuration > 50) do
+ fFrameDuration := fFrameDuration/10;
+ fFrameDuration := 1/fFrameDuration;
end;
- Log.LogInfo('VideoTimeBase: ' + floattostr(fTimeBase), 'TVideoPlayback_ffmpeg.Open');
- Log.LogInfo('Framerate: '+inttostr(floor(1/fTimeBase))+'fps', 'TVideoPlayback_ffmpeg.Open');
+ Log.LogInfo('Framerate: '+inttostr(floor(1/fFrameDuration))+'fps', 'TVideoPlayback_ffmpeg.Open');
{$IFDEF UseSWScale}
// if available get a SWScale-context -> faster than the deprecated img_convert().
@@ -484,7 +509,7 @@ begin
fOpened := False;
fPaused := False;
- fTimeBase := 0;
+ fFrameDuration := 0;
fFrameTime := 0;
fStream := nil;
fStreamIndex := -1;
@@ -498,6 +523,22 @@ begin
fPboId := 0;
fAspectCorrection := acoCrop;
+
+ fScreen := 1;
+
+ fPosX := 0;
+ fPosY := 0;
+ fPosZ := 0;
+ fWidth := RenderW;
+ fHeight := RenderH;
+
+ fFrameRange.Left := 0;
+ fFrameRange.Right := 1;
+ fFrameRange.Upper := 0;
+ fFrameRange.Lower := 1;
+
+ fAlpha := 1;
+ fReflectionSpacing := 0;
end;
procedure TVideo_FFmpeg.Close;
@@ -686,12 +727,6 @@ begin
Exit;
{*
- * TODO:
- * Check if it is correct to assume that fTimeBase is the time of one frame?
- * The tutorial and FFPlay do not make this assumption.
- *}
-
- {*
* Synchronization - begin
*}
@@ -710,12 +745,12 @@ begin
{$IFDEF DebugDisplay}
DebugWriteln('Time: '+inttostr(floor(Time*1000)) + sLineBreak +
'VideoTime: '+inttostr(floor(fFrameTime*1000)) + sLineBreak +
- 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak +
+ 'TimeBase: '+inttostr(floor(fFrameDuration*1000)) + sLineBreak +
'TimeDiff: '+inttostr(floor(TimeDifference*1000)));
{$endif}
// check if time has reached the next frame
- if (TimeDiff < fTimeBase) then
+ if (TimeDiff < fFrameDuration) then
begin
{$ifdef DebugFrames}
// frame delay debug display
@@ -726,7 +761,7 @@ begin
DebugWriteln('not getting new frame' + sLineBreak +
'Time: '+inttostr(floor(Time*1000)) + sLineBreak +
'VideoTime: '+inttostr(floor(fFrameTime*1000)) + sLineBreak +
- 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak +
+ 'TimeBase: '+inttostr(floor(fFrameDuration*1000)) + sLineBreak +
'TimeDiff: '+inttostr(floor(TimeDifference*1000)));
{$endif}
@@ -745,9 +780,9 @@ begin
// check if we have to skip frames
// Either if we are one frame behind or if the skip threshold has been reached.
- // Do not skip if the difference is less than fTimeBase as there is no next frame.
- // Note: We assume that fTimeBase is the length of one frame.
- if (TimeDiff >= Max(fTimeBase, SKIP_FRAME_DIFF)) then
+ // Do not skip if the difference is less than fFrameDuration as there is no next frame.
+ // Note: We assume that fFrameDuration is the length of one frame.
+ if (TimeDiff >= Max(fFrameDuration, SKIP_FRAME_DIFF)) then
begin
{$IFDEF DebugFrames}
//frame drop debug display
@@ -755,13 +790,13 @@ begin
{$ENDIF}
{$IFDEF DebugDisplay}
DebugWriteln('skipping frames' + sLineBreak +
- 'TimeBase: '+inttostr(floor(fTimeBase*1000)) + sLineBreak +
+ 'TimeBase: '+inttostr(floor(fFrameDuration*1000)) + sLineBreak +
'TimeDiff: '+inttostr(floor(TimeDifference*1000)));
{$endif}
// update video-time
- DropFrameCount := Trunc(TimeDiff / fTimeBase);
- fFrameTime := fFrameTime + DropFrameCount*fTimeBase;
+ DropFrameCount := Trunc(TimeDiff / fFrameDuration);
+ fFrameTime := fFrameTime + DropFrameCount*fFrameDuration;
// skip frames
for i := 1 to DropFrameCount do
@@ -889,72 +924,142 @@ procedure TVideo_FFmpeg.GetVideoRect(var ScreenRect, TexRect: TRectCoords);
var
ScreenAspect: double; // aspect of screen resolution
ScaledVideoWidth, ScaledVideoHeight: double;
+
begin
// Three aspects to take into account:
// 1. Screen/display resolution (e.g. 1920x1080 -> 16:9)
- // 2. Render aspect (fixed to 800x600 -> 4:3)
+ // 2. Render aspect (fWidth x fHeight -> variable)
// 3. Movie aspect (video frame aspect stored in fAspect)
- ScreenAspect := ScreenW / ScreenH;
+ ScreenAspect := fWidth*((ScreenW/Screens)/RenderW)/(fHeight*(ScreenH/RenderH));
case fAspectCorrection of
acoStretch: begin
- ScaledVideoWidth := RenderW;
- ScaledVideoHeight := RenderH;
+ ScaledVideoWidth := fWidth;
+ ScaledVideoHeight := fHeight;
end;
+
acoCrop: begin
if (ScreenAspect >= fAspect) then
begin
- ScaledVideoWidth := RenderW;
- ScaledVideoHeight := RenderH * ScreenAspect/fAspect;
- end
- else
+ ScaledVideoWidth := fWidth;
+ ScaledVideoHeight := fHeight * ScreenAspect/fAspect;
+ end else
begin
- ScaledVideoHeight := RenderH;
- ScaledVideoWidth := RenderW * fAspect/ScreenAspect;
+ ScaledVideoHeight := fHeight;
+ ScaledVideoWidth := fWidth * fAspect/ScreenAspect;
end;
end;
+
acoLetterBox: begin
- ScaledVideoWidth := RenderW;
- ScaledVideoHeight := RenderH * ScreenAspect/fAspect;
- end
- else
+ if (ScreenAspect <= fAspect) then
+ begin
+ ScaledVideoWidth := fWidth;
+ ScaledVideoHeight := fHeight * ScreenAspect/fAspect;
+ end else
+ begin
+ ScaledVideoHeight := fHeight;
+ ScaledVideoWidth := fWidth * fAspect/ScreenAspect;
+ end;
+ end else
raise Exception.Create('Unhandled aspect correction!');
end;
- // center video
- ScreenRect.Left := (RenderW - ScaledVideoWidth) / 2;
+ //center video
+ ScreenRect.Left := (fWidth - ScaledVideoWidth) / 2 + fPosX;
ScreenRect.Right := ScreenRect.Left + ScaledVideoWidth;
- ScreenRect.Upper := (RenderH - ScaledVideoHeight) / 2;
+ ScreenRect.Upper := (fHeight - ScaledVideoHeight) / 2 + fPosY;
ScreenRect.Lower := ScreenRect.Upper + ScaledVideoHeight;
// texture contains right/lower (power-of-2) padding.
// Determine the texture coords of the video frame.
- TexRect.Left := 0;
- TexRect.Right := fCodecContext^.width / fTexWidth;
- TexRect.Upper := 0;
- TexRect.Lower := fCodecContext^.height / fTexHeight;
+ TexRect.Left := (fCodecContext^.width / fTexWidth) * fFrameRange.Left;
+ TexRect.Right := (fCodecContext^.width / fTexWidth) * fFrameRange.Right;
+ TexRect.Upper := (fCodecContext^.height / fTexHeight) * fFrameRange.Upper;
+ TexRect.Lower := (fCodecContext^.height / fTexHeight) * fFrameRange.Lower;
end;
-procedure TVideo_FFmpeg.DrawGL(Screen: integer);
-var
- ScreenRect: TRectCoords;
- TexRect: TRectCoords;
+procedure TVideo_FFmpeg.DrawBorders(ScreenRect: TRectCoords);
+ procedure DrawRect(left, right, upper, lower: double);
+ begin
+ glColor4f(0, 0, 0, fAlpha);
+ glBegin(GL_QUADS);
+ glVertex3f(left, upper, fPosZ);
+ glVertex3f(right, upper, fPosZ);
+ glVertex3f(right, lower, fPosZ);
+ glVertex3f(left, lower, fPosZ);
+ glEnd;
+ end;
begin
- // have a nice black background to draw on
- // (even if there were errors opening the vid)
- // TODO: Philipp: IMO TVideoPlayback should not clear the screen at
- // all, because clearing is already done by the background class
- // at this moment.
- if (Screen = 1) then
+ //upper border
+ if(ScreenRect.Upper > fPosY) then
+ DrawRect(fPosX, fPosX+fWidth, fPosY, ScreenRect.Upper);
+
+ //lower border
+ if(ScreenRect.Lower < fPosY+fHeight) then
+ DrawRect(fPosX, fPosX+fWidth, ScreenRect.Lower, fPosY+fHeight);
+
+ //left border
+ if(ScreenRect.Left > fPosX) then
+ DrawRect(fPosX, ScreenRect.Left, fPosY, fPosY+fHeight);
+
+ //right border
+ if(ScreenRect.Right < fPosX+fWidth) then
+ DrawRect(ScreenRect.Right, fPosX+fWidth, fPosY, fPosY+fHeight);
+end;
+
+procedure TVideo_FFmpeg.DrawBordersReflected(ScreenRect: TRectCoords; AlphaUpper, AlphaLower: double);
+var
+ rPosUpper, rPosLower: double;
+
+ procedure DrawRect(left, right, upper, lower: double);
+ var
+ AlphaTop: double;
+ AlphaBottom: double;
+
begin
- // It is important that we just clear once before we start
- // drawing the first screen otherwise the first screen
- // would be cleared by the drawgl called when the second
- // screen is drawn
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+ AlphaTop := AlphaUpper+(AlphaLower-AlphaUpper)*(upper-rPosUpper)/(fHeight*ReflectionH);
+ AlphaBottom := AlphaLower+(AlphaUpper-AlphaLower)*(rPosLower-lower)/(fHeight*ReflectionH);
+
+ glBegin(GL_QUADS);
+ glColor4f(0, 0, 0, AlphaTop);
+ glVertex3f(left, upper, fPosZ);
+ glVertex3f(right, upper, fPosZ);
+
+ glColor4f(0, 0, 0, AlphaBottom);
+ glVertex3f(right, lower, fPosZ);
+ glVertex3f(left, lower, fPosZ);
+ glEnd;
end;
+begin
+ rPosUpper := fPosY+fHeight+fReflectionSpacing;
+ rPosLower := rPosUpper+fHeight*ReflectionH;
+
+ //upper border
+ if(ScreenRect.Upper > rPosUpper) then
+ DrawRect(fPosX, fPosX+fWidth, rPosUpper, ScreenRect.Upper);
+ //lower border
+ if(ScreenRect.Lower < rPosLower) then
+ DrawRect(fPosX, fPosX+fWidth, ScreenRect.Lower, rPosLower);
+
+ //left border
+ if(ScreenRect.Left > fPosX) then
+ DrawRect(fPosX, ScreenRect.Left, rPosUpper, rPosLower);
+
+ //right border
+ if(ScreenRect.Right < fPosX+fWidth) then
+ DrawRect(ScreenRect.Right, fPosX+fWidth, rPosUpper, rPosLower);
+end;
+
+
+procedure TVideo_FFmpeg.Draw();
+var
+ ScreenRect: TRectCoords;
+ TexRect: TRectCoords;
+ HeightFactor: double;
+ WidthFactor: double;
+
+begin
// exit if there's nothing to draw
if (not fOpened) then
Exit;
@@ -966,31 +1071,53 @@ begin
// get texture and screen positions
GetVideoRect(ScreenRect, TexRect);
- // we could use blending for brightness control, but do we need this?
- glDisable(GL_BLEND);
+ WidthFactor := (ScreenW/Screens) / RenderW;
+ HeightFactor := ScreenH / RenderH;
+
+ glScissor(
+ round(fPosX*WidthFactor + (ScreenW/Screens)*(fScreen-1)),
+ round((RenderH-fPosY-fHeight)*HeightFactor),
+ round(fWidth*WidthFactor),
+ round(fHeight*HeightFactor)
+ );
+
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glDepthRange(0, 10);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fFrameTex);
- glColor3f(1, 1, 1);
+ glColor4f(1, 1, 1, fAlpha);
glBegin(GL_QUADS);
// upper-left coord
glTexCoord2f(TexRect.Left, TexRect.Upper);
- glVertex2f(ScreenRect.Left, ScreenRect.Upper);
+ glVertex3f(ScreenRect.Left, ScreenRect.Upper, fPosZ);
// lower-left coord
glTexCoord2f(TexRect.Left, TexRect.Lower);
- glVertex2f(ScreenRect.Left, ScreenRect.Lower);
+ glVertex3f(ScreenRect.Left, ScreenRect.Lower, fPosZ);
// lower-right coord
glTexCoord2f(TexRect.Right, TexRect.Lower);
- glVertex2f(ScreenRect.Right, ScreenRect.Lower);
+ glVertex3f(ScreenRect.Right, ScreenRect.Lower, fPosZ);
// upper-right coord
glTexCoord2f(TexRect.Right, TexRect.Upper);
- glVertex2f(ScreenRect.Right, ScreenRect.Upper);
+ glVertex3f(ScreenRect.Right, ScreenRect.Upper, fPosZ);
glEnd;
+
glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ //draw black borders
+ DrawBorders(ScreenRect);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
{$IFDEF VideoBenchmark}
Log.BenchmarkEnd(15);
- Log.LogBenchmark('DrawGL', 15);
+ Log.LogBenchmark('Draw', 15);
{$ENDIF}
{$IF Defined(Info) or Defined(DebugFrames)}
@@ -998,10 +1125,98 @@ begin
{$IFEND}
end;
+procedure TVideo_FFmpeg.DrawReflection();
+var
+ ScreenRect: TRectCoords;
+ TexRect: TRectCoords;
+ HeightFactor: double;
+ WidthFactor: double;
+
+ AlphaTop: double;
+ AlphaBottom: double;
+
+ AlphaUpper: double;
+ AlphaLower: double;
+
+begin
+ // exit if there's nothing to draw
+ if (not fOpened) then
+ Exit;
+
+ // get texture and screen positions
+ GetVideoRect(ScreenRect, TexRect);
+
+ WidthFactor := (ScreenW/Screens) / RenderW;
+ HeightFactor := ScreenH / RenderH;
+
+ glScissor(
+ round(fPosX*WidthFactor + (ScreenW/Screens)*(fScreen-1)),
+ round((RenderH-fPosY-fHeight-fReflectionSpacing-fHeight*ReflectionH)*HeightFactor),
+ round(fWidth*WidthFactor),
+ round(fHeight*HeightFactor*ReflectionH)
+ );
+
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glDepthRange(0, 10);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, fFrameTex);
+
+ //calculate new ScreenRect coordinates for Reflection
+ ScreenRect.Lower := fPosY + fHeight + fReflectionSpacing
+ + (ScreenRect.Upper-fPosY) + (ScreenRect.Lower-ScreenRect.Upper)*ReflectionH;
+ ScreenRect.Upper := fPosY + fHeight + fReflectionSpacing
+ + (ScreenRect.Upper-fPosY);
+
+ AlphaUpper := fAlpha-0.3;
+ AlphaLower := 0;
+
+ AlphaTop := AlphaUpper-(AlphaLower-AlphaUpper)*
+ (ScreenRect.Upper-fPosY-fHeight-fReflectionSpacing)/fHeight;
+ AlphaBottom := AlphaLower+(AlphaUpper-AlphaLower)*
+ (fPosY+fHeight+fReflectionSpacing+fHeight*ReflectionH-ScreenRect.Lower)/fHeight;
+
+ glBegin(GL_QUADS);
+ //Top Left
+ glColor4f(1, 1, 1, AlphaTop);
+ glTexCoord2f(TexRect.Left, TexRect.Lower);
+ glVertex3f(ScreenRect.Left, ScreenRect.Upper, fPosZ);
+
+ //Bottom Left
+ glColor4f(1, 1, 1, AlphaBottom);
+ glTexCoord2f(TexRect.Left, (TexRect.Lower-TexRect.Upper)*(1-ReflectionH));
+ glVertex3f(ScreenRect.Left, ScreenRect.Lower, fPosZ);
+
+ //Bottom Right
+ glColor4f(1, 1, 1, AlphaBottom);
+ glTexCoord2f(TexRect.Right, (TexRect.Lower-TexRect.Upper)*(1-ReflectionH));
+ glVertex3f(ScreenRect.Right, ScreenRect.Lower, fPosZ);
+
+ //Top Right
+ glColor4f(1, 1, 1, AlphaTop);
+ glTexCoord2f(TexRect.Right, TexRect.Lower);
+ glVertex3f(ScreenRect.Right, ScreenRect.Upper, fPosZ);
+ glEnd;
+
+ glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ //draw black borders
+ DrawBordersReflected(ScreenRect, AlphaUpper, AlphaLower);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+end;
+
procedure TVideo_FFmpeg.ShowDebugInfo();
begin
{$IFDEF Info}
- if (fFrameTime+fTimeBase < 0) then
+ if (fFrameTime+fFrameDuration < 0) then
begin
glColor4f(0.7, 1, 0.3, 1);
SetFontStyle (1);
@@ -1093,7 +1308,10 @@ begin
fEOF := false;
fFrameTexValid := false;
- if (av_seek_frame(fFormatContext, fStreamIndex, Floor(Time/fTimeBase), SeekFlags) < 0) then
+ if (av_seek_frame(fFormatContext,
+ fStreamIndex,
+ Round(Time / av_q2d(fStream^.time_base)),
+ SeekFlags) < 0) then
begin
Log.LogError('av_seek_frame() failed', 'TVideoPlayback_ffmpeg.SetPosition');
Exit;
@@ -1107,6 +1325,111 @@ begin
Result := fFrameTime;
end;
+procedure TVideo_FFmpeg.SetScreen(Screen: integer);
+begin
+ fScreen := Screen;
+end;
+
+function TVideo_FFmpeg.GetScreen(): integer;
+begin
+ Result := fScreen;
+end;
+
+
+procedure TVideo_FFmpeg.SetScreenPosition(X, Y, Z: double);
+begin
+ fPosX := X;
+ fPosY := Y;
+ fPosZ := Z;
+end;
+
+procedure TVideo_FFmpeg.GetScreenPosition(var X, Y, Z: double);
+begin
+ X := fPosX;
+ Y := fPosY;
+ Z := fPosZ;
+end;
+
+
+procedure TVideo_FFmpeg.SetWidth(Width: double);
+begin
+ fWidth := Width;
+end;
+
+function TVideo_FFmpeg.GetWidth(): double;
+begin
+ Result := fWidth;
+end;
+
+
+procedure TVideo_FFmpeg.SetHeight(Height: double);
+begin
+ fHeight := Height;
+end;
+
+function TVideo_FFmpeg.GetHeight(): double;
+begin
+ Result := fHeight;
+end;
+
+
+procedure TVideo_FFmpeg.SetFrameRange(Range: TRectCoords);
+begin
+ fFrameRange := Range;
+end;
+
+function TVideo_FFmpeg.GetFrameRange(): TRectCoords;
+begin
+ Result := fFrameRange;
+end;
+
+
+function TVideo_FFmpeg.GetFrameAspect(): real;
+begin
+ Result := fAspect;
+end;
+
+
+procedure TVideo_FFmpeg.SetAspectCorrection(AspectCorrection: TAspectCorrection);
+begin
+ fAspectCorrection := AspectCorrection;
+end;
+
+function TVideo_FFmpeg.GetAspectCorrection(): TAspectCorrection;
+begin
+ Result := fAspectCorrection;
+end;
+
+
+
+procedure TVideo_FFmpeg.SetAlpha(Alpha: double);
+begin
+ fAlpha := Alpha;
+
+ if (fAlpha>1) then
+ fAlpha := 1;
+
+ if (fAlpha<0) then
+ fAlpha := 0;
+end;
+
+function TVideo_FFmpeg.GetAlpha(): double;
+begin
+ Result := fAlpha;
+end;
+
+
+procedure TVideo_FFmpeg.SetReflectionSpacing(Spacing: double);
+begin
+ fReflectionSpacing := Spacing;
+end;
+
+function TVideo_FFmpeg.GetReflectionSpacing(): double;
+begin
+ Result := fReflectionSpacing;
+end;
+
+
initialization
MediaManager.Add(TVideoPlayback_FFmpeg.Create);
diff --git a/us_maker_edition/src/media/UVisualizer.pas b/us_maker_edition/src/media/UVisualizer.pas
index 4f553521..1cdc3500 100644
--- a/us_maker_edition/src/media/UVisualizer.pas
+++ b/us_maker_edition/src/media/UVisualizer.pas
@@ -110,6 +110,8 @@ type
fState: TProjectMState;
+ fScreen: integer;
+
fVisualTex: GLuint;
fPCMData: TPCMData;
fRndPCMcount: integer;
@@ -144,8 +146,35 @@ type
procedure SetLoop(Enable: boolean);
function GetLoop(): boolean;
+ procedure SetScreen(Screen: integer);
+ function GetScreen(): integer;
+
+ procedure SetScreenPosition(X, Y, Z: double);
+ procedure GetScreenPosition(var X, Y, Z: double);
+
+ procedure SetWidth(Width: double);
+ function GetWidth(): double;
+
+ procedure SetHeight(Height: double);
+ function GetHeight(): double;
+
+ procedure SetFrameRange(Range: TRectCoords);
+ function GetFrameRange(): TRectCoords;
+
+ function GetFrameAspect(): real;
+
+ procedure SetAspectCorrection(AspectCorrection: TAspectCorrection);
+ function GetAspectCorrection(): TAspectCorrection;
+
+ procedure SetAlpha(Alpha: double);
+ function GetAlpha(): double;
+
+ procedure SetReflectionSpacing(Spacing: double);
+ function GetReflectionSpacing(): double;
+
procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
+ procedure Draw();
+ procedure DrawReflection();
end;
TVideoPlayback_ProjectM = class( TInterfacedObject, IVideoVisualization )
@@ -262,6 +291,88 @@ begin
Result := true;
end;
+procedure TVideo_ProjectM.SetScreen(Screen: integer);
+begin
+end;
+
+function TVideo_ProjectM.GetScreen(): integer;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_ProjectM.SetScreenPosition(X, Y, Z: double);
+begin
+end;
+
+procedure TVideo_ProjectM.GetScreenPosition(var X, Y, Z: double);
+begin
+ X := 0;
+ Y := 0;
+ Z := 0;
+end;
+
+procedure TVideo_ProjectM.SetWidth(Width: double);
+begin
+end;
+
+function TVideo_ProjectM.GetWidth(): double;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_ProjectM.SetHeight(Height: double);
+begin
+end;
+
+function TVideo_ProjectM.GetHeight(): double;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_ProjectM.SetFrameRange(Range: TRectCoords);
+begin
+end;
+
+function TVideo_ProjectM.GetFrameRange(): TRectCoords;
+begin
+ Result.Left := 0;
+ Result.Right := 0;
+ Result.Upper := 0;
+ Result.Lower := 0;
+end;
+
+function TVideo_ProjectM.GetFrameAspect(): real;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_ProjectM.SetAspectCorrection(AspectCorrection: TAspectCorrection);
+begin
+end;
+
+function TVideo_ProjectM.GetAspectCorrection(): TAspectCorrection;
+begin
+ Result := acoStretch;
+end;
+
+procedure TVideo_ProjectM.SetAlpha(Alpha: double);
+begin
+end;
+
+function TVideo_ProjectM.GetAlpha(): double;
+begin
+ Result := 1;
+end;
+
+procedure TVideo_ProjectM.SetReflectionSpacing(Spacing: double);
+begin
+end;
+
+function TVideo_ProjectM.GetReflectionSpacing(): double;
+begin
+ Result := 0;
+end;
+
{**
* Returns the stack depth of the given OpenGL matrix mode stack.
*}
@@ -485,11 +596,11 @@ end;
* Draws the current frame to screen.
* TODO: this is not used yet. Data is directly drawn on GetFrame().
*}
-procedure TVideo_ProjectM.DrawGL(Screen: integer);
+procedure TVideo_ProjectM.Draw();
begin
{$IFDEF UseTexture}
// have a nice black background to draw on
- if (Screen = 1) then
+ if (fScreen = 1) then
begin
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
@@ -521,10 +632,10 @@ begin
// draw projectM frame
// Screen is 1 to 2. So current screen is from (Screen - 1) to (Screen)
glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f((Screen - 1), 0);
- glTexCoord2f(1, 0); glVertex2f(Screen, 0);
- glTexCoord2f(1, 1); glVertex2f(Screen, 1);
- glTexCoord2f(0, 1); glVertex2f((Screen - 1), 1);
+ glTexCoord2f(0, 0); glVertex2f((fScreen - 1), 0);
+ glTexCoord2f(1, 0); glVertex2f(fScreen, 0);
+ glTexCoord2f(1, 1); glVertex2f(fScreen, 1);
+ glTexCoord2f(0, 1); glVertex2f((fScreen - 1), 1);
glEnd();
glDisable(GL_TEXTURE_2D);
@@ -538,6 +649,10 @@ begin
{$ENDIF}
end;
+procedure TVideo_ProjectM.DrawReflection();
+begin
+end;
+
{**
* Produces random "sound"-data in case no audio-data is available.
* Otherwise the visualization will look rather boring.
diff --git a/us_maker_edition/src/menu/UDisplay.pas b/us_maker_edition/src/menu/UDisplay.pas
index e3ec272a..6ec8e2ed 100644
--- a/us_maker_edition/src/menu/UDisplay.pas
+++ b/us_maker_edition/src/menu/UDisplay.pas
@@ -51,12 +51,12 @@ type
ePreDraw: THookableEvent;
eDraw: THookableEvent;
- //fade-to-black-hack
+ // fade-to-black
BlackScreen: boolean;
FadeEnabled: boolean; // true if fading is enabled
FadeFailed: boolean; // true if fading is possible (enough memory, etc.)
- FadeTime: cardinal; // time when fading starts, 0 means that the fade texture must be initialized
+ FadeStartTime: cardinal; // time when fading starts, 0 means that the fade texture must be initialized
DoneOnShow: boolean; // true if passed onShow after fading
FadeTex: array[0..1] of GLuint;
@@ -87,7 +87,7 @@ type
NextScreen: PMenu;
CurrentScreen: PMenu;
- //popup data
+ // popup data
NextScreenWithCheck: Pmenu;
CheckOK: boolean;
@@ -130,12 +130,12 @@ var
const
{ constants for screen transition
time in milliseconds }
- Transition_Fade_Time = 400;
+ FADE_DURATION = 400;
{ constants for software cursor effects
time in milliseconds }
- Cursor_FadeIn_Time = 500; // seconds the fade in effect lasts
- Cursor_FadeOut_Time = 2000; // seconds the fade out effect lasts
- Cursor_AutoHide_Time = 5000; // seconds until auto fade out starts if there is no mouse movement
+ CURSOR_FADE_IN_TIME = 500; // seconds the fade in effect lasts
+ CURSOR_FADE_OUT_TIME = 2000; // seconds the fade out effect lasts
+ CURSOR_AUTOHIDE_TIME = 5000; // seconds until auto fade out starts if there is no mouse movement
implementation
@@ -160,14 +160,14 @@ begin
ePreDraw := THookableEvent.Create('Display.PreDraw');
eDraw := THookableEvent.Create('Display.Draw');
- //popup hack
+ // init popup
CheckOK := false;
NextScreen := nil;
NextScreenWithCheck := nil;
BlackScreen := false;
- // fade mod
- FadeTime := 0;
+ // init fade
+ FadeStartTime := 0;
FadeEnabled := (Ini.ScreenFade = 1);
FadeFailed := false;
DoneOnShow := false;
@@ -175,7 +175,7 @@ begin
glGenTextures(2, PGLuint(@FadeTex));
InitFadeTextures();
- //Set LastError for OSD to No Error
+ // set LastError for OSD to No Error
OSD_LastError := 'No Errors';
// software cursor default values
@@ -222,11 +222,6 @@ var
begin
Result := true;
- //We don't need this here anymore,
- //Because the background care about cleaning the buffers
- //glClearColor(1, 1, 1 , 0);
- //glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
-
for S := 1 to Screens do
begin
ScreenAct := S;
@@ -238,8 +233,7 @@ begin
glViewPort((S-1) * ScreenW div Screens, 0, ScreenW div Screens, ScreenH);
- // popup hack
- // check was successful... move on
+ // popup check was successful... move on
if CheckOK then
begin
if assigned(NextScreenWithCheck) then
@@ -260,7 +254,7 @@ begin
ePreDraw.CallHookChain(false);
CurrentScreen.Draw;
- //popup mod
+ // popup
if (ScreenPopupError <> nil) and ScreenPopupError.Visible then
ScreenPopupError.Draw
else if (ScreenPopupInfo <> nil) and ScreenPopupInfo.Visible then
@@ -268,11 +262,11 @@ begin
else if (ScreenPopupCheck <> nil) and ScreenPopupCheck.Visible then
ScreenPopupCheck.Draw;
- // fade mod
- FadeTime := 0;
+ // fade
+ FadeStartTime := 0;
if ((Ini.ScreenFade = 1) and (not FadeFailed)) then
FadeEnabled := true
- else if (Ini.ScreenFade = 0) then
+ else
FadeEnabled := false;
eDraw.CallHookChain(false);
@@ -287,8 +281,8 @@ begin
if (FadeEnabled and not FadeFailed) then
begin
- //Create Fading texture if we're just starting
- if FadeTime = 0 then
+ // create fading texture if we're just starting
+ if FadeStartTime = 0 then
begin
// draw screen that will be faded
ePreDraw.CallHookChain(false);
@@ -319,7 +313,6 @@ begin
Log.LogError('Fading disabled: ' + gluErrorString(glError), 'TDisplay.Draw');
end;
- // blackscreen-hack
if not BlackScreen and (S = 1) and not DoneOnShow then
begin
NextScreen.OnShow;
@@ -329,18 +322,9 @@ begin
// set fade time once on second screen (or first if screens = 1)
if (Screens = 1) or (S = 2) then
- FadeTime := SDL_GetTicks;
+ FadeStartTime := SDL_GetTicks;
end; // end texture creation in first fading step
- {//do some time-based fading
- currentTime := SDL_GetTicks();
- if (currentTime > LastFadeTime+30) and (S = 1) then
- begin
- FadeState := FadeState + 5;
- LastFadeTime := currentTime;
- end; }
-
- // blackscreen-hack
if not BlackScreen then
begin
ePreDraw.CallHookChain(false);
@@ -349,15 +333,16 @@ begin
end
else if ScreenAct = 1 then
begin
+ // draw black screen
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;
// and draw old screen over it... slowly fading out
- if (FadeTime = 0) then
+ if (FadeStartTime = 0) then
FadeStateSquare := 0 // for first screen if screens = 2
else
- FadeStateSquare := sqr((SDL_GetTicks - FadeTime) / Transition_Fade_Time);
+ FadeStateSquare := sqr((SDL_GetTicks - FadeStartTime) / FADE_DURATION);
if (FadeStateSquare < 1) then
begin
@@ -392,17 +377,19 @@ begin
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
end;
end
-
- // blackscreen hack
+
+ // there is no need to init next screen if it is a black screen
else if not BlackScreen then
begin
NextScreen.OnShow;
end;
- if ((FadeTime + Transition_Fade_Time < SDL_GetTicks) or (not FadeEnabled) or FadeFailed) and ((Screens = 1) or (S = 2)) then
+ if ((FadeStartTime + FADE_DURATION < SDL_GetTicks) or
+ (not FadeEnabled) or FadeFailed) and
+ ((Screens = 1) or (S = 2)) then
begin
// fade out complete...
- FadeTime := 0;
+ FadeStartTime := 0;
DoneOnShow := false;
CurrentScreen.onHide;
CurrentScreen.ShowFinish := false;
@@ -421,7 +408,7 @@ begin
end;
end; // if
-// Draw OSD only on first Screen if Debug Mode is enabled
+ // Draw OSD only on first Screen if Debug Mode is enabled
if ((Ini.Debug = 1) or (Params.Debug)) and (S = 1) then
DrawDebugInformation;
@@ -485,7 +472,7 @@ begin
if (not Cursor_Visible) and (Cursor_LastMove <> 0) then
begin
if Cursor_Fade then // we use a trick here to consider progress of fade out
- Cursor_LastMove := Ticks - round(Cursor_FadeIn_Time * (1 - (Ticks - Cursor_LastMove)/Cursor_FadeOut_Time))
+ Cursor_LastMove := Ticks - round(CURSOR_FADE_IN_TIME * (1 - (Ticks - Cursor_LastMove)/CURSOR_FADE_OUT_TIME))
else
Cursor_LastMove := Ticks;
@@ -533,7 +520,7 @@ begin
begin // draw software cursor
Ticks := SDL_GetTicks;
- if (Cursor_Visible) and (Cursor_LastMove + Cursor_AutoHide_Time <= Ticks) then
+ if (Cursor_Visible) and (Cursor_LastMove + CURSOR_AUTOHIDE_TIME <= Ticks) then
begin // start fade out after 5 secs w/o activity
Cursor_Visible := false;
Cursor_LastMove := Ticks;
@@ -545,17 +532,17 @@ begin
begin
if Cursor_Visible then
begin // fade in
- if (Cursor_LastMove + Cursor_FadeIn_Time <= Ticks) then
+ if (Cursor_LastMove + CURSOR_FADE_IN_TIME <= Ticks) then
Cursor_Fade := false
else
- Alpha := sin((Ticks - Cursor_LastMove) * 0.5 * pi / Cursor_FadeIn_Time) * 0.7;
+ Alpha := sin((Ticks - Cursor_LastMove) * 0.5 * pi / CURSOR_FADE_IN_TIME) * 0.7;
end
else
begin //fade out
- if (Cursor_LastMove + Cursor_FadeOut_Time <= Ticks) then
+ if (Cursor_LastMove + CURSOR_FADE_OUT_TIME <= Ticks) then
Cursor_Fade := false
else
- Alpha := cos((Ticks - Cursor_LastMove) * 0.5 * pi / Cursor_FadeOut_Time) * 0.7;
+ Alpha := cos((Ticks - Cursor_LastMove) * 0.5 * pi / CURSOR_FADE_OUT_TIME) * 0.7;
end;
end;
diff --git a/us_maker_edition/src/menu/UMenuBackgroundVideo.pas b/us_maker_edition/src/menu/UMenuBackgroundVideo.pas
index bfaee702..9a33e721 100644
--- a/us_maker_edition/src/menu/UMenuBackgroundVideo.pas
+++ b/us_maker_edition/src/menu/UMenuBackgroundVideo.pas
@@ -151,14 +151,14 @@ begin
glClear(GL_DEPTH_BUFFER_BIT);
// video failure -> draw blank background
if (fBgVideo = nil) then
- glClear(GL_COLOR_BUFFER_BIT);
+ glClear(GL_COLOR_BUFFER_BIT);
end;
if (fBgVideo <> nil) then
begin
fBgVideo.GetFrame(VideoBGTimer.GetTime());
- // FIXME: why do we draw on screen 2? Seems to be wrong.
- fBgVideo.DrawGL(2);
+ fBgVideo.SetScreen(ScreenAct);
+ fBgVideo.Draw();
end;
end;
diff --git a/us_maker_edition/src/screens/UScreenEditSub.pas b/us_maker_edition/src/screens/UScreenEditSub.pas
index 400053c0..51e1df42 100644
--- a/us_maker_edition/src/screens/UScreenEditSub.pas
+++ b/us_maker_edition/src/screens/UScreenEditSub.pas
@@ -52,6 +52,7 @@ uses
gl,
{$IFDEF UseMIDIPort}
MidiOut,
+ MidiCons,
{$ENDIF}
UThemes,
UPath;
@@ -485,7 +486,11 @@ begin
Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntNormal
else
Lines[0].Line[Lines[0].Current].Note[CurrentNote].NoteType := ntFreestyle;
- GoldenRec.KillAll;
+ GoldenRec.KillAll;
+
+ // update lyrics
+ Lyric.AddLine(Lines[0].Current);
+ Lyric.Selected := CurrentNote;
Exit;
end;
SDLK_Z:
@@ -667,18 +672,35 @@ begin
SDLK_SPACE:
begin
- // Play Sentence
- PlaySentenceMidi := false; // stop midi
- PlaySentence := true;
- Click := false;
- AudioPlayback.Stop;
- AudioPlayback.Position := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start);
- PlayStopTime := (GetTimeFromBeat(
- Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start +
- Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length));
- AudioPlayback.SetVolume(SelectsS[VolumeAudioSlideId].SelectedOption / 100);
- AudioPlayback.Play;
- LastClick := -100;
+ if (SDL_ModState = 0) or (SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL) then
+ begin
+ // Play Sentence
+ PlaySentenceMidi := false; // stop midi
+ PlaySentence := true;
+ Click := false;
+ AudioPlayback.Stop;
+ AudioPlayback.Position := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start);
+ PlayStopTime := (GetTimeFromBeat(
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start +
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length));
+ AudioPlayback.SetVolume(SelectsS[VolumeAudioSlideId].SelectedOption / 100);
+ AudioPlayback.Play;
+ LastClick := -100;
+ end;
+
+ if (SDL_ModState = KMOD_LSHIFT) or (SDL_ModState = KMOD_LSHIFT or KMOD_LCTRL) then
+ begin
+ // Play Midi
+ PlaySentenceMidi := true;
+
+ MidiTime := USTime.GetTime;
+ MidiStart := GetTimeFromBeat(Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start);
+ MidiStop := GetTimeFromBeat(
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start +
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length);
+
+ LastClick := -100;
+ end;
end;
SDLK_RETURN:
@@ -718,7 +740,7 @@ begin
begin
if SDL_ModState = KMOD_LCTRL then
begin
- // moves text to right in current sentence
+ // deletes current note
CopyToUndo;
DeleteNote;
GoldenRec.KillAll;
@@ -878,7 +900,7 @@ begin
begin
{$IFDEF UseMIDIPort}
MidiOut.PutShort($B1, $7, floor(1.27*SelectsS[VolumeMidiSlideId].SelectedOption));
- MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
+ MidiOut.PutShort(MIDI_NOTEOFF or 1, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
PlaySentenceMidi := false;
{$ENDIF}
@@ -915,7 +937,7 @@ begin
AudioPlayback.Stop;
PlaySentence := false;
{$IFDEF UseMIDIPort}
- MidiOut.PutShort($B1, $7, floor(1.27*SelectsS[VolumeMidiSlideId].SelectedOption));
+ MidiOut.PutShort(MIDI_NOTEOFF or 1, $7, floor(1.27*SelectsS[VolumeMidiSlideId].SelectedOption));
MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
PlaySentenceMidi := false;
{$endif}
@@ -1445,13 +1467,21 @@ begin
Note[N] := Note[N-1];
end;
- // me slightly modify new note
- Note[CurrentNote].Length := 1;
- Inc(Note[CurrentNote+1].Start);
- Dec(Note[CurrentNote+1].Length);
- Note[CurrentNote+1].Text := '- ';
+ // Note[Cur] and Note[Cur + 1] is identical at this point
+ // modify first note
+ Note[CurrentNote].Length := Note[CurrentNote+1].Length div 2 + Note[CurrentNote+1].Length mod 2;
+
+ // 2nd note
+ Note[CurrentNote+1].Start := Note[CurrentNote].Start + Note[CurrentNote].Length;
+ Note[CurrentNote+1].Length := Note[CurrentNote + 1].Length div 2;
+
+ Note[CurrentNote+1].Text := '~';
Note[CurrentNote+1].Color := 1;
end;
+
+ // update lyric display
+ Lyric.AddLine(Lines[0].Current);
+ Lyric.Selected := CurrentNote;
end;
procedure TScreenEditSub.DeleteNote;
@@ -1462,9 +1492,8 @@ begin
C := Lines[0].Current;
//Do Not delete Last Note
- if (Lines[0].High > 0) or (Lines[0].Line[C].HighNote > 0) then
+ if (Lines[0].Line[C].HighNote > 0) then
begin
-
// we copy all notes from the next to the selected one
for N := CurrentNote+1 to Lines[0].Line[C].HighNote do
begin
@@ -1472,37 +1501,47 @@ begin
end;
Dec(Lines[0].Line[C].HighNote);
- if (Lines[0].Line[C].HighNote >= 0) then
- begin
- SetLength(Lines[0].Line[C].Note, Lines[0].Line[C].HighNote + 1);
- // me slightly modify new note
- if CurrentNote > Lines[0].Line[C].HighNote then
- Dec(CurrentNote);
-
- Lines[0].Line[C].Note[CurrentNote].Color := 2;
- end
- //Last Note of current Sentence Deleted - > Delete Sentence
- else
+ SetLength(Lines[0].Line[C].Note, Lines[0].Line[C].HighNote + 1);
+
+ // last note was deleted
+ if (CurrentNote > Lines[0].Line[C].HighNote) then
begin
- //Move all Sentences after the current to the Left
- for N := C+1 to Lines[0].High do
- Lines[0].Line[N-1] := Lines[0].Line[N];
-
- //Delete Last Sentence
- SetLength(Lines[0].Line, Lines[0].High);
- Lines[0].High := High(Lines[0].Line);
- Lines[0].Number := Length(Lines[0].Line);
-
- CurrentNote := 0;
- if (C > 0) then
- Lines[0].Current := C - 1
- else
- Lines[0].Current := 0;
-
- Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 2;
+ // select new last note
+ CurrentNote := Lines[0].Line[C].HighNote;
+
+ // correct Line ending
+ with Lines[0].Line[C] do
+ End_ := Note[HighNote].Start + Note[HighNote].Length;
end;
+
+ Lines[0].Line[C].Note[CurrentNote].Color := 2;
+ end
+ // Last Note of current Sentence Deleted - > Delete Sentence
+ // if there are more than two left
+ else if (Lines[0].High > 1) then
+ begin
+ //Move all Sentences after the current to the Left
+ for N := C+1 to Lines[0].High do
+ Lines[0].Line[N-1] := Lines[0].Line[N];
+
+ //Delete Last Sentence
+ SetLength(Lines[0].Line, Lines[0].High);
+ Lines[0].High := High(Lines[0].Line);
+ Lines[0].Number := Length(Lines[0].Line);
+
+ CurrentNote := 0;
+ if (C > 0) then
+ Lines[0].Current := C - 1
+ else
+ Lines[0].Current := 0;
+
+ Lines[0].Line[Lines[0].Current].Note[CurrentNote].Color := 2;
end;
+
+ // update lyric display
+ Lyric.AddLine(Lines[0].Current);
+ Lyric.Selected := CurrentNote;
end;
procedure TScreenEditSub.TransposeNote(Transpose: integer);
@@ -1896,6 +1935,7 @@ end;
procedure TScreenEditSub.DrawInfoBar(x, y, w, h: integer);
var
start, end_: integer;
+ SongStart, SongEnd: integer;
ww: integer;
pos: real;
@@ -1910,9 +1950,9 @@ begin
if(numLines=0) then
Exit;
- start := Lines[0].Line[0].Start;
- end_ := Lines[0].Line[numLines-1].End_;
- ww := end_ - start;
+ SongStart := Lines[0].Line[0].Note[0].Start;
+ SongEnd := Lines[0].Line[numLines-1].End_;
+ ww := SongEnd - SongStart;
glColor4f(0, 0, 0, 1);
glDisable(GL_BLEND);
@@ -1945,7 +1985,7 @@ begin
end_ := Lines[0].Line[line].Note[Lines[0].Line[line].HighNote].Start+
Lines[0].Line[line].Note[Lines[0].Line[line].HighNote].Length;
- pos := start/ww*w;
+ pos := (start - SongStart)/ww*w;
br := (end_-start)/ww*w;
glbegin(gl_quads);
@@ -1954,26 +1994,19 @@ begin
glVertex2f(x+pos+br, y+h);
glVertex2f(x+pos+br, y);
glEnd;
- {
- numNotes := Length(Lines[0].Line[line].Nuta);
-
- for note := 0 to numNotes - 1 do
- begin
-
- end; }
end;
if(PlaySentence or PlaySentenceMidi) then
begin
glColor4f(0, 0, 0, 0.5);
pos := 0;
- br := AktBeat/ww*w;
+ br := (AktBeat - SongStart)/ww*w;
if (br>w) then
br := w;
end else
begin
glColor4f(1, 0, 0, 1);
- pos := Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start/ww*w;
+ pos := (Lines[0].Line[Lines[0].Current].Note[CurrentNote].Start - SongStart)/ww*w;
br := Lines[0].Line[Lines[0].Current].Note[CurrentNote].Length/ww*w;
if (br<1) then
br := 1;
@@ -2316,7 +2349,7 @@ begin
end;
-// Interaction := 0;
+ //Interaction := 0;
TextEditMode := false;
TitleEditMode := false;
ArtistEditMode := false;
@@ -2344,7 +2377,7 @@ begin
if (MidiPos > MidiStop) then
begin
MidiOut.PutShort($B1, $7, floor(1.27*SelectsS[VolumeMidiSlideId].SelectedOption));
- MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
+ MidiOut.PutShort(MIDI_NOTEOFF or 1, Lines[0].Line[Lines[0].Current].Note[MidiLastNote].Tone + 60, 127);
PlaySentenceMidi := false;
end;
{$ENDIF}
@@ -2363,7 +2396,7 @@ begin
{$IFDEF UseMIDIPort}
MidiOut.PutShort($B1, $7, floor(1.27*SelectsS[VolumeMidiSlideId].SelectedOption));
if i > 0 then
- MidiOut.PutShort($81, Lines[0].Line[Lines[0].Current].Note[i-1].Tone + 60, 127);
+ MidiOut.PutShort(MIDI_NOTEOFF or 1, Lines[0].Line[Lines[0].Current].Note[i-1].Tone + 60, 127);
MidiOut.PutShort($91, Lines[0].Line[Lines[0].Current].Note[i].Tone + 60, 127);
MidiLastNote := i;
{$ENDIF}
@@ -2421,7 +2454,7 @@ begin
// click
if (Click) and (PlaySentence) then
begin
-// AktBeat := Floor(CurrentSong.BPM[0].BPM * (Music.Position - CurrentSong.GAP / 1000) / 60);
+ //AktBeat := Floor(CurrentSong.BPM[0].BPM * (Music.Position - CurrentSong.GAP / 1000) / 60);
AktBeat := Floor(GetMidBeat(AudioPlayback.Position - CurrentSong.GAP / 1000));
Text[TextDebug].Text := IntToStr(AktBeat);
if AktBeat <> LastClick then
diff --git a/us_maker_edition/src/screens/UScreenOptionsRecord.pas b/us_maker_edition/src/screens/UScreenOptionsRecord.pas
index 0f9cd49a..dc4a355f 100644
--- a/us_maker_edition/src/screens/UScreenOptionsRecord.pas
+++ b/us_maker_edition/src/screens/UScreenOptionsRecord.pas
@@ -88,6 +88,7 @@ type
procedure StartPreview;
procedure StopPreview;
procedure UpdateInputDevice;
+ function ValidateSettings: boolean;
procedure ChangeVolume(VolumeChange: single);
procedure DrawVolume(x, y, Width, Height: single);
procedure DrawVUMeter(const State: TDrawState; x, y, Width, Height: single);
@@ -120,6 +121,7 @@ uses
TextGL,
UGraphic,
UDraw,
+ ULanguage,
UMain,
UMenuSelectSlide,
UMenuText,
@@ -168,7 +170,7 @@ begin
SDLK_BACKSPACE:
begin
// TODO: Show Save/Abort screen
- if (AudioInputProcessor.ValidateSettings()) then
+ if (ValidateSettings()) then
begin
Ini.Save;
AudioPlayback.PlaySound(SoundLib.Back);
@@ -179,7 +181,7 @@ begin
begin
if (SelInteraction = ExitButtonIID) then
begin
- if (AudioInputProcessor.ValidateSettings()) then
+ if (ValidateSettings()) then
begin
Ini.Save;
AudioPlayback.PlaySound(SoundLib.Back);
@@ -213,6 +215,24 @@ begin
end;
end;
+function TScreenOptionsRecord.ValidateSettings: boolean;
+var
+ BadPlayer: integer;
+begin
+ BadPlayer := AudioInputProcessor.ValidateSettings();
+ if (BadPlayer <> 0) then
+ begin
+ ScreenPopupError.ShowPopup(
+ Format(Language.Translate('ERROR_PLAYER_DEVICE_ASSIGNMENT'),
+ [BadPlayer]));
+ Result := false;
+ end
+ else
+ begin
+ Result := true;
+ end;
+end;
+
constructor TScreenOptionsRecord.Create;
var
DeviceIndex: integer;
@@ -321,12 +341,6 @@ begin
end;
// add Exit-button
- //ButtonTheme := Theme.OptionsRecord.ButtonExit;
- // adjust button position
- //if (WidgetYPos <> 0) then
- // ButtonTheme.Y := WidgetYPos;
- //AddButton(ButtonTheme);
- // <mog> I uncommented the stuff above, because it's not skinable :X
AddButton(Theme.OptionsRecord.ButtonExit);
if (Length(Button[0].Text) = 0) then
AddButtonText(20, 5, Theme.Options.Description[7]);
@@ -783,7 +797,7 @@ begin
for ChannelIndex := 0 to High(Device.CaptureChannel) do
begin
// load player color mapped to current input channel
- if (DeviceCfg.ChannelToPlayerMap[ChannelIndex] > 0) then
+ if (DeviceCfg.ChannelToPlayerMap[ChannelIndex] <> CHANNEL_OFF) then
begin
// set mapped channel to corresponding player-color
LoadColor(State.R, State.G, State.B, 'P'+ IntToStr(DeviceCfg.ChannelToPlayerMap[ChannelIndex]) + 'Dark');
diff --git a/us_maker_edition/src/screens/UScreenOptionsThemes.pas b/us_maker_edition/src/screens/UScreenOptionsThemes.pas
index 94475cc7..29d8a9dc 100644
--- a/us_maker_edition/src/screens/UScreenOptionsThemes.pas
+++ b/us_maker_edition/src/screens/UScreenOptionsThemes.pas
@@ -92,6 +92,10 @@ begin
UGraphic.LoadScreens();
AudioPlayback.PlaySound(SoundLib.Back);
+
+ // select theme button in new created options screen
+ ScreenOptions.Interaction := 4;
+
FadeTo(@ScreenOptions);
end;
SDLK_RETURN:
@@ -106,6 +110,10 @@ begin
UGraphic.LoadScreens();
AudioPlayback.PlaySound(SoundLib.Back);
+
+ // select theme button in new created options screen
+ ScreenOptions.Interaction := 4;
+
FadeTo(@ScreenOptions);
end;
end;
diff --git a/us_maker_edition/src/screens/UScreenSing.pas b/us_maker_edition/src/screens/UScreenSing.pas
index 233f1e38..3e0d8078 100644
--- a/us_maker_edition/src/screens/UScreenSing.pas
+++ b/us_maker_edition/src/screens/UScreenSing.pas
@@ -62,6 +62,12 @@ type
function GetClock(): real; override;
end;
+ TTimebarMode = (
+ tbmCurrent, // current song position
+ tbmRemaining, // remaining time
+ tbmTotal // total time
+ );
+
type
TScreenSing = class(TMenu)
private
@@ -70,6 +76,7 @@ type
fVideoClip: IVideo;
fLyricsSync: TLyricsSyncSource;
fMusicSync: TMusicSyncSource;
+ fTimebarMode: TTimebarMode;
protected
eSongLoaded: THookableEvent; //< event is called after lyrics of a song are loaded on OnShow
Paused: boolean; //pause Mod
@@ -178,7 +185,9 @@ begin
Result := false;
Exit;
end;
- Ord('V'): // show visualization
+
+ // show visualization
+ Ord('V'):
begin
fShowVisualization := not fShowVisualization;
@@ -193,11 +202,23 @@ begin
end;
Exit;
end;
+
+ // pause
Ord('P'):
begin
Pause;
Exit;
end;
+
+ // toggle time display
+ Ord('T'):
+ begin
+ if (fTimebarMode = High(TTimebarMode)) then
+ fTimebarMode := Low(TTimebarMode)
+ else
+ Inc(fTimebarMode);
+ Exit;
+ end;
end;
// check special keys
@@ -349,6 +370,7 @@ var
Color: TRGB;
VideoFile, BgFile: IPath;
success: boolean;
+ BadPlayer: integer;
begin
inherited;
@@ -450,6 +472,8 @@ begin
Statics[StaticP3R].Visible := V3R;
Text[TextP3R].Visible := V3R;
+ fTimebarMode := tbmCurrent;
+
// FIXME: sets path and filename to ''
ResetSingTemp;
@@ -498,7 +522,7 @@ begin
*}
fShowVisualization := false;
VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
- if (CurrentSong.Video.IsSet) and VideoFile.IsFile then
+ if (Ini.VideoEnabled = 1) and CurrentSong.Video.IsSet() and VideoFile.IsFile then
begin
fVideoClip := VideoPlayback.Open(VideoFile);
fCurrentVideo := fVideoClip;
@@ -562,6 +586,14 @@ begin
LyricsState.TotalTime := AudioPlayback.Length;
LyricsState.UpdateBeats();
+ BadPlayer := AudioInputProcessor.CheckPlayersConfig(PlayersPlay);
+ if (BadPlayer <> 0) then
+ begin
+ ScreenPopupError.ShowPopup(
+ Format(Language.Translate('ERROR_PLAYER_NO_DEVICE_ASSIGNMENT'),
+ [BadPlayer]));
+ end;
+
// prepare and start voice-capture
AudioInput.CaptureStart;
@@ -725,8 +757,10 @@ end;
function TScreenSing.Draw: boolean;
var
- Min: integer;
- Sec: integer;
+ DisplayTime: real;
+ DisplayPrefix: string;
+ DisplayMin: integer;
+ DisplaySec: integer;
T: integer;
CurLyricsTime: real;
VideoFrameTime: Extended;
@@ -769,53 +803,31 @@ begin
end; // case
end; // if
- ////
- // dual screen, part 1
- ////////////////////////
-
- // Note: ScreenX is the offset of the current screen in dual-screen mode so we
- // will move the statics and texts to the correct screen here.
- // FIXME: clean up this weird stuff. Commenting this stuff out, nothing
- // was missing on screen w/ 6 players - so do we even need this stuff?
- {Statics[StaticP1].Texture.X := Statics[StaticP1].Texture.X + 10 * ScreenX;
-
- Text[TextP1].X := Text[TextP1].X + 10 * ScreenX; }
-
- {Statics[StaticP1ScoreBG].Texture.X := Statics[StaticP1ScoreBG].Texture.X + 10*ScreenX;
- Text[TextP1Score].X := Text[TextP1Score].X + 10*ScreenX;}
-
- {Statics[StaticP2R].Texture.X := Statics[StaticP2R].Texture.X + 10 * ScreenX;
-
- Text[TextP2R].X := Text[TextP2R].X + 10 * ScreenX; }
-
- {Statics[StaticP2RScoreBG].Texture.X := Statics[StaticP2RScoreBG].Texture.X + 10*ScreenX;
- Text[TextP2RScore].X := Text[TextP2RScore].X + 10*ScreenX;}
-
- // end of weird stuff
- {
- Statics[1].Texture.X := Statics[1].Texture.X + 10 * ScreenX; }
-
- { for T := 0 to 1 do
- Text[T].X := Text[T].X + 10 * ScreenX; }
-
// retrieve current lyrics time, we have to store the value to avoid
// that min- and sec-values do not match
CurLyricsTime := LyricsState.GetCurrentTime();
- Min := Round(CurLyricsTime) div 60;
- Sec := Round(CurLyricsTime) mod 60;
+
+ // retrieve time for timebar text
+ case (fTimebarMode) of
+ tbmRemaining: begin
+ DisplayTime := LyricsState.TotalTime - CurLyricsTime;
+ DisplayPrefix := '-';
+ end;
+ tbmTotal: begin
+ DisplayTime := LyricsState.TotalTime;
+ DisplayPrefix := '#';
+ end;
+ else begin
+ DisplayTime := CurLyricsTime;
+ DisplayPrefix := '';
+ end;
+ end;
+ DisplayMin := Round(DisplayTime) div 60;
+ DisplaySec := Round(DisplayTime) mod 60;
// update static menu with time ...
- Text[TextTimeText].Text := '';
- if Min < 10 then
- Text[TextTimeText].Text := '0';
- Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Min) + ':';
- if Sec < 10 then
- Text[TextTimeText].Text := Text[TextTimeText].Text + '0';
- Text[TextTimeText].Text := Text[TextTimeText].Text + IntToStr(Sec);
-
- // draw static menu (BG)
- // Note: there is no menu and the animated background brakes the video playback
- //DrawBG;
+ Text[TextTimeText].Text := Format('%s%.2d:%.2d',
+ [DisplayPrefix, DisplayMin, DisplaySec]);
//the song was sung to the end?
Line := Lyrics.GetUpperLine();
@@ -847,7 +859,8 @@ begin
fCurrentVideo.GetFrame(VideoFrameTime);
end;
- fCurrentVideo.DrawGL(ScreenAct);
+ fCurrentVideo.SetScreen(ScreenAct);
+ fCurrentVideo.Draw;
end;
// draw static menu (FG)
@@ -857,8 +870,10 @@ begin
//Log.LogError('Check for music finish: ' + BoolToStr(Music.Finished) + ' ' + FloatToStr(LyricsState.CurrentTime*1000) + ' ' + IntToStr(CurrentSong.Finish));
if ShowFinish then
begin
- if (not AudioPlayback.Finished) and ((CurrentSong.Finish = 0) or
- (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) and (not Settings.Finish) then
+ if (not AudioPlayback.Finished) and
+ ((CurrentSong.Finish = 0) or
+ (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) and
+ (not Settings.Finish) then
begin
// analyze song if not paused
if (not Paused) then
@@ -886,27 +901,6 @@ begin
// draw scores
Scores.Draw;
- ////
- // dual screen, part 2
- ////////////////////////
-
- // Note: ScreenX is the offset of the current screen in dual-screen mode so we
- // will move the statics and texts to the correct screen here.
- // FIXME: clean up this weird stuff
-
- {Statics[StaticP1].Texture.X := Statics[StaticP1].Texture.X - 10 * ScreenX;
- Text[TextP1].X := Text[TextP1].X - 10 * ScreenX;
-
- Statics[StaticP2R].Texture.X := Statics[StaticP2R].Texture.X - 10 * ScreenX;
- Text[TextP2R].X := Text[TextP2R].X - 10 * ScreenX;
-
- // end of weird
-
- Statics[1].Texture.X := Statics[1].Texture.X - 10 * ScreenX;
-
- for T := 0 to 1 do
- Text[T].X := Text[T].X - 10 * ScreenX; }
-
// draw pausepopup
// FIXME: this is a workaround that the static is drawn over the lyrics, lines, scores and effects
// maybe someone could find a better solution
diff --git a/us_maker_edition/src/screens/UScreenSong.pas b/us_maker_edition/src/screens/UScreenSong.pas
index 6b83d522..6fe8d204 100644
--- a/us_maker_edition/src/screens/UScreenSong.pas
+++ b/us_maker_edition/src/screens/UScreenSong.pas
@@ -62,8 +62,12 @@ type
isScrolling: boolean; // true if song flow is about to move
+ fCurrentVideo: IVideo;
+
procedure StartMusicPreview();
procedure StopMusicPreview();
+ procedure StartVideoPreview();
+ procedure StopVideoPreview();
public
TextArtist: integer;
TextTitle: integer;
@@ -128,6 +132,7 @@ type
function Draw: boolean; override;
procedure GenerateThumbnails();
procedure OnShow; override;
+ procedure OnShowFinish; override;
procedure OnHide; override;
procedure SelectNext;
procedure SelectPrev;
@@ -886,6 +891,8 @@ begin
PreviewOpened := -1;
isScrolling := false;
+
+ fCurrentVideo := nil;
end;
procedure TScreenSong.GenerateThumbnails();
@@ -960,6 +967,7 @@ begin
if (Ini.PreviewVolume <> 0) then
begin
StartMusicPreview;
+ StartVideoPreview;
end;
// fade in detailed cover
@@ -973,6 +981,7 @@ begin
UnLoadDetailedCover;
StopMusicPreview();
+ StopVideoPreview();
PreviewOpened := -1;
end;
@@ -1506,6 +1515,9 @@ begin
AudioPlayback.Stop;
PreviewOpened := -1;
+ // reset video playback engine
+ fCurrentVideo := nil;
+
if Ini.Players <= 3 then PlayersPlay := Ini.Players + 1;
if Ini.Players = 4 then PlayersPlay := 6;
@@ -1544,11 +1556,17 @@ begin
end;
end;
- isScrolling := true;
+ isScrolling := false;
SetJoker;
SetStatics;
end;
+procedure TScreenSong.OnShowFinish;
+begin
+ isScrolling := true;
+ CoverTime := 10;
+end;
+
procedure TScreenSong.OnHide;
begin
// turn music volume to 100%
@@ -1556,6 +1574,7 @@ begin
// stop preview
StopMusicPreview();
+ StopVideoPreview();
end;
procedure TScreenSong.DrawExtensions;
@@ -1573,9 +1592,10 @@ end;
function TScreenSong.Draw: boolean;
var
- dx: real;
- dt: real;
- I: integer;
+ dx: real;
+ dt: real;
+ I: integer;
+ VideoAlpha: real;
begin
if isScrolling then
begin
@@ -1611,7 +1631,7 @@ begin
//Log.LogBenchmark('SetScroll4', 5);
//Fading Functions, Only if Covertime is under 5 Seconds
- if (CoverTime < 5) then
+ if (CoverTime < 9) then
begin
// cover fade
if (CoverTime < 1) and (CoverTime + TimeSkip >= 1) then
@@ -1641,10 +1661,43 @@ begin
//Draw BG
DrawBG;
+ VideoAlpha := Button[interaction].Texture.Alpha*(CoverTime-1);
//Instead of Draw FG Procedure:
//We draw Buttons for our own
for I := 0 to Length(Button) - 1 do
- Button[I].Draw;
+ begin
+ if (I<>Interaction) or not Assigned(fCurrentVideo) or (VideoAlpha<1) or AudioPlayback.Finished then
+ Button[I].Draw;
+ end;
+
+ if AudioPlayback.Finished then
+ StopVideoPreview;
+
+ if Assigned(fCurrentVideo) then
+ begin
+ // Just call this once
+ // when Screens = 2
+ if (ScreenAct = 1) then
+ fCurrentVideo.GetFrame(CatSongs.Song[Interaction].VideoGAP + AudioPlayback.Position);
+
+ fCurrentVideo.SetScreen(ScreenAct);
+ fCurrentVideo.Alpha := VideoAlpha;
+
+ //set up window
+ with Button[interaction] do
+ begin
+ fCurrentVideo.SetScreenPosition(X, Y, Z);
+ fCurrentVideo.Width := W;
+ fCurrentVideo.Height := H;
+ fCurrentVideo.ReflectionSpacing := Reflectionspacing;
+ end;
+ fCurrentVideo.AspectCorrection := acoCrop;
+
+ fCurrentVideo.Draw;
+
+ if Button[interaction].Reflection then
+ fCurrentVideo.DrawReflection;
+ end;
// Statics
for I := 0 to Length(Statics) - 1 do
@@ -1738,12 +1791,13 @@ end;
procedure TScreenSong.StartMusicPreview();
var
Song: TSong;
+ PreviewPos: real;
begin
AudioPlayback.Close();
if CatSongs.VisibleSongs = 0 then
Exit;
-
+
Song := CatSongs.Song[Interaction];
if not assigned(Song) then
Exit;
@@ -1755,8 +1809,13 @@ begin
if AudioPlayback.Open(Song.Path.Append(Song.Mp3)) then
begin
PreviewOpened := Interaction;
-
- AudioPlayback.Position := AudioPlayback.Length / 4;
+
+ PreviewPos := AudioPlayback.Length / 4;
+ // fix for invalid music file lengths
+ if (PreviewPos > 60.0) then
+ PreviewPos := 60.0;
+ AudioPlayback.Position := PreviewPos;
+
// set preview volume
if (Ini.PreviewFading = 0) then
begin
@@ -1779,12 +1838,66 @@ begin
AudioPlayback.Stop;
end;
+procedure TScreenSong.StartVideoPreview();
+var
+ VideoFile: IPath;
+ Song: TSong;
+
+begin
+ if (Ini.VideoPreview=0) then
+ Exit;
+
+ if Assigned(fCurrentVideo) then
+ begin
+ fCurrentVideo.Stop();
+ fCurrentVideo := nil;
+ end;
+
+ //if no audio open => exit
+ if (PreviewOpened = -1) then
+ Exit;
+
+ if CatSongs.VisibleSongs = 0 then
+ Exit;
+
+ Song := CatSongs.Song[Interaction];
+ if not assigned(Song) then
+ Exit;
+
+ //fix: if main cat than there is nothing to play
+ if Song.main then
+ Exit;
+
+ VideoFile := Song.Path.Append(Song.Video);
+ if (Song.Video.IsSet) and VideoFile.IsFile then
+ begin
+ fCurrentVideo := VideoPlayback.Open(VideoFile);
+ if (fCurrentVideo <> nil) then
+ begin
+ fCurrentVideo.Position := Song.VideoGAP + AudioPlayback.Position;
+ fCurrentVideo.Play;
+ end;
+ end;
+end;
+
+procedure TScreenSong.StopVideoPreview();
+begin
+ // Stop video preview of previous song
+ if Assigned(fCurrentVideo) then
+ begin
+ fCurrentVideo.Stop();
+ fCurrentVideo := nil;
+ end;
+end;
+
// Changes previewed song
procedure TScreenSong.ChangeMusic;
begin
StopMusicPreview();
+ StopVideoPreview();
PreviewOpened := -1;
StartMusicPreview();
+ StartVideoPreview();
end;
procedure TScreenSong.SkipTo(Target: cardinal);