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
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
- PAL Scripting - "Hello World" Example and Using Pal For Category Based Rotation
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);
