Browse Source

* Player demo

Michaël Van Canneyt 3 năm trước cách đây
mục cha
commit
49b0ae4bec

BIN
demo/player/headset.jpeg


+ 54 - 0
demo/player/index.html

@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <title>Media player demo</title>
+  <link rel="stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
+  <link rel="stylesheet" type="text/css" href="style.css">
+  <script src="tracks.js"></script>
+  <script src="main.js"></script>
+</head>
+<body>
+  <div class="player">
+  
+    <div class="details">
+      <div class="display-text"></div>
+      <div class="now-playing">PLAYING x OF y</div>
+      <div class="track-art"></div>
+      <div class="track-name">Track Name</div>
+      <div class="track-artist">Track Artist</div>
+    </div>
+  
+    <div class="buttons">
+      <div class="prev-track" >
+        <i class="fa fa-step-backward fa-2x"></i>
+      </div>
+      <div class="playpause-track">
+        <i class="fa fa-play-circle fa-5x"></i>
+      </div>
+      <div class="next-track" >
+        <i class="fa fa-step-forward fa-2x"></i>
+      </div>
+    </div>
+  
+    <div class="slider_container">
+      <div class="current-time">00:00</div>
+      <input type="range" min="1" max="100"
+        value="0" class="seek_slider" >
+      <div class="total-duration">00:00</div>
+    </div>
+  
+    <div class="slider_container">
+      <i class="fa fa-volume-down"></i>
+      <input type="range" min="1" max="100"
+        value="99" class="volume_slider">
+      <i class="fa fa-volume-up"></i>
+    </div>
+  </div>
+  <hr>
+  <a href="main.pas">Program sources</a>  &nbsp; <a
+   href="https://www.bensound.com/royalty-free-music/">Royalty-free music from Bensound</a> 
+  <script>
+     window.addEventListener("load",rtl.run)
+  </script>
+</body>
+</html>

+ 81 - 0
demo/player/main.lpi

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+        <Runnable Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="main"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="2">
+      <Item0 Name="PasJSPort" Value="0"/>
+      <Item1 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="main.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="main"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 229 - 0
demo/player/main.pas

@@ -0,0 +1,229 @@
+program main;
+
+{$mode objfpc}
+
+uses
+  browserapp, JS, Classes, SysUtils, Web;
+
+type
+  TTrack = Record
+    name,
+    artist,
+    image,
+    path,
+    display,
+    url : String;
+  end;
+
+  TMyApplication = class(TBrowserApplication)
+    now_playing,
+    track_art,
+    track_name,
+    track_artist,
+    display_text,
+    playpause_btn,
+    next_btn,
+    prev_btn,
+    curr_time,
+    total_duration : TJSHTMLElement;
+    curr_track : TJSHTMLAudioElement;
+    volume_slider,
+    seek_slider : TJSHTMLinputElement;
+    isPlaying : Boolean;
+    track_index : Integer;
+    updateTimer: Integer;
+    Procedure BindElements;
+    Procedure seekTo(Event: TJSEvent);
+    Procedure SetVolume(Event: TJSEvent);
+    Procedure DoPlayPause(Event: TJSEvent);
+    Procedure NextTrack(Event: TJSEvent);
+    Procedure PrevTrack(Event: TJSEvent);
+    Procedure PlayTrack;
+    Procedure PauseTrack;
+    procedure LoadTrack(aIndex : Integer);
+    procedure random_bg_color;
+    procedure resetValues;
+    procedure seekUpdate;
+    procedure doRun; override;
+  private
+  end;
+
+var
+  track_list : Array of TTrack; external name 'track_list';
+
+
+procedure TMyApplication.seekUpdate;
+
+Var
+  seekPosition : Double;
+  currentMinutes,
+  currentSeconds,
+  durationMinutes,
+  durationSeconds : Integer;
+
+begin
+  if jsIsNan(curr_track.duration) then exit;
+  seekPosition:=curr_track.currentTime * (100 / curr_track.duration);
+  seek_slider.value :=FloatToStr(seekPosition);
+  currentMinutes:=Round(curr_track.currentTime / 60);
+  currentSeconds:=Round(curr_track.currentTime - currentMinutes * 60);
+  durationMinutes:=Round(curr_track.duration / 60);
+  durationSeconds:=Round(curr_track.duration - durationMinutes * 60);
+  curr_time.innerText:= Format('%.2:%d2',[currentMinutes,currentSeconds]);
+  total_duration.innerText:=Format('%.2:%d2',[durationMinutes,durationSeconds]);
+end;
+
+procedure TMyApplication.BindElements;
+
+  Function GetElement (aClass : String) : TJSHTMLELement;
+
+  begin
+
+    Result:=TJSHTMLELement(Document.querySelector('.'+aClass));
+    Writeln('Looking for ',aClass,' : ',assigned(Result));
+  end;
+
+begin
+  now_playing :=GetElement('now-playing');
+  track_art :=GetElement('track-art');
+  track_name :=GetElement('track-name');
+  track_artist :=GetElement('track-artist');
+  display_text :=GetElement('display-text');
+
+  playpause_btn :=GetElement('playpause-track');
+  playpause_btn.AddEventListener('click',@DoPlayPause);
+  next_btn :=GetElement('next-track');
+  next_btn.AddEventListener('click',@NextTrack);
+  prev_btn :=GetElement('prev-track');
+  prev_btn.AddEventListener('click',@PrevTrack);
+  seek_slider :=TJSHTMLInputElement(GetElement('seek_slider'));
+  seek_slider.AddEventListener('change',@SeekTo);
+  volume_slider :=TJSHTMLInputElement(GetElement('volume_slider'));
+  volume_slider.AddEventListener('change',@SetVolume);
+  curr_time :=GetElement('current-time');
+  total_duration :=GetElement('total-duration');
+end;
+
+procedure TMyApplication.seekTo(Event: TJSEvent);
+
+Var
+  dSeekTo : Double;
+
+begin
+  dSeekTo := curr_track.duration * (StrToFloatDef(seek_slider.value,50) / 100);
+  curr_track.currentTime := dSeekTo;
+end;
+
+procedure TMyApplication.SetVolume(Event: TJSEvent);
+begin
+  curr_track.volume := StrToFloatDef(volume_slider.value,50) / 100;
+end;
+
+procedure TMyApplication.DoPlayPause(Event: TJSEvent);
+begin
+  if isPlaying then
+    pauseTrack
+  else
+    playTrack;
+end;
+
+procedure TMyApplication.NextTrack(Event: TJSEvent);
+begin
+  // Go back to the first track if the
+  // current one is the last in the track list
+  if (track_index < (Length(track_list) - 1)) then
+    Inc(track_index)
+  else
+    track_index:=0;
+  // Load and play the new track
+  loadTrack(track_index);
+  playTrack();
+end;
+
+procedure TMyApplication.PrevTrack(Event: TJSEvent);
+begin
+  if (track_index > 0) then
+    Dec(track_index)
+  else
+   track_index := Length(track_list)- 1;
+  loadTrack(track_index);
+  playTrack();
+end;
+
+procedure TMyApplication.PlayTrack;
+begin
+  curr_track.play();
+  isPlaying:=true;
+  playpause_btn.innerHTML := '<i class="fa fa-pause-circle fa-5x"></i>';
+end;
+
+procedure TMyApplication.PauseTrack;
+begin
+  curr_track.pause();
+  isPlaying:=false;
+  playpause_btn.innerHTML := '<i class="fa fa-play-circle fa-5x"></i>';
+end;
+
+procedure TMyApplication.LoadTrack(aIndex: Integer);
+begin
+  // Clear the previous seek timer
+  window.clearInterval(updateTimer);
+  resetValues();
+
+  curr_track.src :=track_list[track_index].path;
+  curr_track.load();
+
+  track_art.style.SetProperty('background-image','url("' + track_list[track_index].image+ '")');
+  track_art.style.SetProperty('background-image','url("' + track_list[track_index].image+ '")');
+  track_artist.InnerHTML := track_list[track_index].artist;
+  track_name.InnerHTML := track_list[track_index].name;
+  display_text.InnerHTML:=String(track_list[track_index].display);
+  now_playing.InnerHTML := Format('PLAYING %d OF %d',[track_index + 1,Length(track_list)]);
+  updateTimer :=Window.setInterval(@seekUpdate, 1000);
+  curr_track.addEventListener('ended', @nextTrack);
+  random_bg_color();
+end;
+
+procedure TMyApplication.random_bg_color;
+
+Const
+    Lim = 256 - 64;
+
+Var
+  red,Green,blue : Integer;
+  col : string;
+begin
+  red:=Round(random(Lim) + 64);
+  green:=Round(random(lim) + 64);
+  blue:=Round(random(lim)+64);
+  col:= Format('rgb(%d,%d,%d)',[red, green ,blue]);
+  TJSHTMLELement(document.body).style.SetProperty('background',col);
+end;
+
+procedure TMyApplication.resetValues;
+begin
+  curr_time.InnerHTML:= '00:00';
+  total_duration.InnerHTML:= '00:00';
+  seek_slider.value:='0';
+end;
+
+procedure TMyApplication.doRun;
+
+begin
+  Terminate;
+  BindElements;
+  curr_track:=TJSHTMLAudioElement(document.createElement('audio'));
+  curr_track.autoplay:=true;
+  ResetValues;
+  Window.SetInterval(@seekUpdate,1000);
+  LoadTrack(0);
+end;
+
+var
+  Application : TMyApplication;
+
+begin
+  Application:=TMyApplication.Create(nil);
+  Application.Initialize;
+  Application.Run;
+end.

+ 143 - 0
demo/player/style.css

@@ -0,0 +1,143 @@
+body {
+background-color: lightgreen;
+
+/* Smoothly transition the background color */
+transition: background-color .5s;
+}
+
+/* Using flex with the column direction to
+align items in a vertical direction */
+.player {
+height: 95vh;
+display: flex;
+align-items: center;
+flex-direction: column;
+justify-content: center;
+}
+
+.details {
+display: flex;
+align-items: center;
+flex-direction: column;
+justify-content: center;
+margin-top: 25px;
+}
+
+.track-art {
+margin: 25px;
+height: 250px;
+width: 250px;
+background-image: URL("headset.jpeg");
+background-size: cover;
+background-position: center;
+border-radius: 15%;
+}
+
+/* Changing the font sizes to suitable ones */
+.now-playing {
+font-size: 1rem;
+}
+
+.track-name {
+font-size: 3rem;
+}
+
+.display-text {
+font-size: 3rem;
+}
+
+.track-artist {
+font-size: 1.5rem;
+}
+
+/* Using flex with the row direction to
+align items in a horizontal direction */
+.buttons {
+display: flex;
+flex-direction: row;
+align-items: center;
+}
+
+.playpause-track,
+.prev-track,
+.next-track {
+padding: 25px;
+opacity: 0.8;
+
+/* Smoothly transition the opacity */
+transition: opacity .2s;
+}
+
+/* Change the opacity when mouse is hovered */
+.playpause-track:hover,
+.prev-track:hover,
+.next-track:hover {
+opacity: 1.0;
+}
+
+/* Define the slider width so that it scales properly */
+.slider_container {
+width: 75%;
+max-width: 400px;
+display: flex;
+justify-content: center;
+align-items: center;
+}
+
+/* Modify the appearance of the slider */
+.seek_slider, .volume_slider {
+-webkit-appearance: none;
+-moz-appearance: none;
+appearance: none;
+height: 5px;
+background: black;
+opacity: 0.7;
+-webkit-transition: .2s;
+transition: opacity .2s;
+}
+
+/* Modify the appearance of the slider thumb */
+.seek_slider::-webkit-slider-thumb,
+.volume_slider::-webkit-slider-thumb {
+-webkit-appearance: none;
+-moz-appearance: none;
+appearance: none;
+width: 15px;
+height: 15px;
+background: white;
+cursor: pointer;
+border-radius: 50%;
+}
+
+/* Change the opacity when mouse is hovered */
+.seek_slider:hover,
+.volume_slider:hover {
+opacity: 1.0;
+}
+
+.seek_slider {
+width: 60%;
+}
+
+.volume_slider {
+width: 30%;
+}
+
+.current-time,
+.total-duration {
+padding: 10px;
+}
+
+i.fa-volume-down,
+i.fa-volume-up {
+padding: 10px;
+}
+
+/* Change the mouse cursor to a pointer
+when hovered over */
+i.fa-play-circle,
+i.fa-pause-circle,
+i.fa-step-forward,
+i.fa-step-backward {
+cursor: pointer;
+}

+ 46 - 0
demo/player/tracks.js

@@ -0,0 +1,46 @@
+
+var track_list = [
+{
+    display: "here we go with our demo!",
+    name: "Epic music",
+    artist: "Bensound epic",
+    image: "https://www.freepascal.org/~michael/pas2js-demos/player/epic.jpg",
+    path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-epic.mp3",
+},
+{
+        display: "Now for something less hard...",
+	name: "Rumble rock",
+	artist: "Bensound rumble",
+	image: "https://www.freepascal.org/~michael/pas2js-demos/player/rumble.jpg",
+	path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-rumble.mp3"
+},
+{
+        display: "We even have dubstep",
+	name: "Dubstep for the fans",
+	artist: "Bensound dubstep",
+	image: "https://www.freepascal.org/~michael/pas2js-demos/player/dubstep.jpg",
+	path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-dubstep.mp3"
+},
+{
+        display: "We also have some pop tunes",
+	name: "Pop tune beyond the line",
+	artist: "Bensound pop tune ",
+	image: "https://www.freepascal.org/~michael/pas2js-demos/player/beyondtheline.jpg",
+	path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-beyondtheline.mp3"
+},
+{
+        display: "Something soundtrack-like.",
+	name: "Once again",
+	artist: "Bensound once again",
+	image: "https://www.freepascal.org/~michael/pas2js-demos/player/onceagain.jpg",
+	path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-onceagain.mp3",
+},
+{
+        display: "And going home with some jazzy tune!",
+	name: "Jazzy lounge",
+	artist: "Bensound the lounge",
+	image: "https://www.freepascal.org/~michael/pas2js-demos/player/thelounge.jpg",
+	path: "https://www.freepascal.org/~michael/pas2js-demos/player/bensound-thelounge.mp3",
+}
+];
+