Note that this Wiki is a work in progress, items may not be updated or may disappear entirely as the pages are updated.

Ammended - Custom Song balance script

From SpacialAudio

Jump to: navigation, search

Link To Other PAL Articles

Table of Contents   Quick Start Guide   PAL Scripting 101   Objects   Script Examples    Music1 24 Hour PAL Script    Music 1 Hourly PAL   CBS News Scripts    Write some useful scripts


Here is Toby's clock wheel with the fix for the 0 duration files. It should keep them from showing up.

PAL.Loop := True;
// Set some global variables to be used throughout the script
  var
   D, D2, D3 : TDataSet;
  var
   scale, points, increments,
   highest_point, songID, count : Integer;
  var
   lowest_point, point_increment, balance, penalty : Float;
  var
   date : DateTime;
   // SET ALL SONG balanceS TO ZERO
  ExecSQL('UPDATE songlist SET balance = 0',[]);

{*******************************************************************************

              START OF RULE 1
*******************************************************************************}
  var current_time :  DateTime = now;
  var three_hours_ago :  DateTime = T['-03:00:00'];

{******************************************************************************

RULE 1: NO SONG REPEATS WITHIN 3 HOURS
This rule applies severe penalties to songs played in the last three hours.
The most recently played tune receives the heaviest penalty. A song played
2 1/2 hours ago receives a lighter penalty. For every second closer to NOW that
a song played, its penalty increases by about 9.25 points.
******************************************************************************}
  Pal.LockExecution;
// SET PENALTY VARIABLES
scale := 100;
points := 100;
increments := 10800;      // the number of sec's in 3 hours
lowest_point := points - ((points / 100) * scale);
highest_point := points;
point_increment := (highest_point - lowest_point) / increments;


D:=Query('SELECT ID, date_played FROM songlist WHERE date_played > :now', [three_hours_ago], True);
D.First;
While Not D.EOF Do
Begin
 // SET NEW balanceS FOR ALL SONGS PLAYED WITHIN LAST 3 HOURS
 date := D['date_played'];
 penalty := ((((date * 86400) - (three_hours_ago * 86400)) * point_increment) + lowest_point);
 ExecSQL('UPDATE songlist SET balance = balance + :penalty WHERE ID = :ID', [penalty, D['ID']]);
 D.Next;
End;
D.Free;
Pal.UnlockExecution;
WriteLn('Rule 1 complete.');
{*******************************************************************************
              END OF RULE 1
*******************************************************************************}



{*******************************************************************************
              START OF RULE 2
*******************************************************************************}
  var lastgenre : String;


{*******************************************************************************
RULE NUMBER 2: DIFFERENT GENRE FOR EACH PLAY
Checks genre of the currently playing song and penalizes all songs that are
from the same genre. This just adds a little variety, especially if you are
running a Top 40 station. For instance it will make sure you don't have two
rap songs back to back, or two pop songs. For this to really work well you
should take the time to go through all of your songs and fine tune the genre
tags. Instead of using the "Rock" genre for all of your fast guitar songs,
sort them into "Hard Rock", "Metal", "Death Metal" etc. Sort your "Rap" genres
into "Hip Hop", "Freestyle", "Gangsta", etc.
Also, this rule only works if you leave SAM on "Ghost Queue" mode, instead
of keeping more than one track in the queue. This rule only applies to the
currently playing song therefore, if you're adding the 5th song to the queue,
only the 5th song will be of a different genre from the one currently playing.
*******************************************************************************}
  Pal.LockExecution;
  penalty := 20;
  // GET GENRE OF LAST SONG PLAYED
  D := Query('SELECT genre FROM songlist ORDER BY date_played DESC LIMIT 1', [], True);
    lastgenre := (D['genre']);
  D.Free;
  // PENALIZE ALL SONGS WITH MATCHING GENRE
  ExecSQL('UPDATE songlist SET balance = balance + :penalty WHERE genre = :lastgenre',[penalty, lastgenre]);
  PAL.UnlockExecution;
  WriteLn('Rule 2 complete.');
{*******************************************************************************
              END OF RULE 2
*******************************************************************************}



{*******************************************************************************
              START OF RULE 3
********************************************************************************
********************************************************************************
RULE 3: NO ARTIST REPEATS WITHIN AN HOUR
All artists that have played in the last 60 minutes will be penalized. Currently
a blanket value of 100 points is assigned to all artists played in the last hour.
(This rule could be made better by checking exactly how long ago that artist was
played and penalizing it differently for each second closer to NOW that the
artist was played - much like the way RULE 1 penalizes songs.I'll probably play
with this a bit after some coffee.)
*******************************************************************************}
Pal.LockExecution;
penalty := 100;
//GRAB ALL ARTISTS FROM LAST HOUR
D := Query('SELECT DISTINCT artist FROM historylist WHERE date_played > :now ORDER BY date_played DESC',[T['-01:00:00']],True);
D.First;
while not D.EOF do
begin
  ExecSQL('UPDATE songlist SET balance = balance + :penalty WHERE artist = :artist',[penalty, D['artist']]);
  D.Next;
end;
D.Free;
PAL.UnlockExecution;
WriteLn('Rule 3 complete.');
{*******************************************************************************
                 END OF RULE 3
********************************************************************************



{*******************************************************************************
              START OF RULE 4
********************************************************************************
********************************************************************************
RULE 4: CHECK QUEUE LIST
This rule double checks the queue list. Any songs that are already queued will
be assigned some penalty points (currently set at 100).
*******************************************************************************}
  Pal.LockExecution;
  penalty := 100;
  //GRAB ALL SONGS FROM QUEUE LIST
  D := Query('SELECT songID FROM queuelist',[],True);
  D.First;
   while not D.EOF do
   begin
     D3 := Query('SELECT artist from songlist WHERE ID = :songID', [D['songID']], True);
     ExecSQL('UPDATE songlist SET balance = balance + :penalty WHERE artist = :artist',[penalty, D3['artist']]);
     D3.Free;
     D.Next;
   end;
  D.Free;


  PAL.UnlockExecution;
  WriteLn('Rule 4 complete.');
{*******************************************************************************
              END OF RULE 4
********************************************************************************}




{*******************************************************************************
              START OF RULE 5
********************************************************************************}
var x : Integer;
{*******************************************************************************

RULE 5: Check number of plays This rule checks how many times each song has played. The more a song has been played the higher the penalty will be. If a song has never played it will end up with a lower balance than the one that has played the most.

********************************************************************************}


PAL.LockExecution;
scale := 100;
points := 100;


// Get highest number of song plays
D := Query('SELECT DISTINCT count_played from songlist ORDER BY count_played DESC LIMIT 1', [], True);
increments := D['count_played'];
D.Free;
lowest_point := points - ((points / 100) * scale);
highest_point := points;
point_increment := (highest_point - lowest_point) / increments;


x := 0;
While x <= increments do
begin
 penalty := x * point_increment;
 ExecSQL('UPDATE songlist SET balance = balance + :penalty WHERE count_played = :x ', [penalty, x]);
 x := x + 1;
end;
PAL.UnlockExecution;
WriteLn('Rule 5 complete.');
{*******************************************************************************
              END OF RULE 5
********************************************************************************}




{*******************************************************************************
              START CHOOSE BEST SONG
********************************************************************************
********************************************************************************
This section grabs the song with the lowest balance. If more than one song
shares the lowest balance, a random one will be chosen with that score.
This section is currently disabled. If you do not have a complex script set up
for category based rotation, you can enable this section to do the song
selection for you. You will be amazed at the consistent results! To enable this
section, just put a closed bracket at the end of the line below this text, just
after the long series of asterisks.
*******************************************************************************}
  WriteLn('Choosing best song...');
  Pal.LockExecution;
 // GRAB LOWEST FINAL balance
  D := Query('SELECT balance FROM songlist ORDER BY balance ASC', [], True);
    balance := D['balance'];
  D.Free;
  // Count number of songs with this balance
  D:= Query('SELECT filename, balance FROM songlist WHERE balance = :balance ORDER BY RAND() LIMIT 1', [balance], True);
  // Que up selected song	
  if FileExists(D['filename']) then
        {Check if file actually exists}
     Queue.AddFile(D['filename'],ipBottom);
   if FileExists(D['filename']) then
     WriteLn('Adding: ' + D['filename'] + ' to queue.')
   else
     WriteLn('file no exist not Adding: ' + D['filename'] + ' to queue.');
  D.Free;
  PAL.UnlockExecution;
{*******************************************************************************
              END CHOOSE BEST SONG
*******************************************************************************}
  // Wait for song to play before running again from the top
  PAL.WaitForPlayCount(1);