Jump to content

Pal Script simple double shot script?


ecvbob

Recommended Posts

Well I bought SAM4 bout 9 months ago just for the great feature called PAL scripts. Little did I realize they work great if you want to learn to be a code writer to use them.

 

I just need a script or whatever to queue and play two songs by a random artist, then repeat with a different artist all day, be a good idea if if followed the playlist rules set fourth.

 

I'm not against learning to help myself but I can't find hardly anything on writing PAL Scripts and well the spacial audity support part of the site and forum has left me wanting to get rid of SAM but I like the other features so I guess I will keep it for now.

 

Script would be nice but any helpful information is appreciated.

 

Bob Mannelin

 

THUNDER711.com

Link to comment
Share on other sites

There is a ton of help on PAL scripts on the Spacial Audio forums. All you need to do is search it out.

 

Here is a 2-fer script, written by FesterHead, that I use on Tuesdays. You can modify the setup and make it work for other days.

 

{
 Don't be a loser.  Leave this here.
 Twofer script by FesterHead (aka Steve Kunitzer)
 $Id: twofer.pal,v 1.6 2006/05/20 20:09:43 FesterHead Exp $
 What this PAL does:
   * Plays twofers
     * artist(2), artist(2), artist(2), ...
 What is configurable:
   * Toggle debug mode
   * Toggle memory leak warning
   * Show updating title, description, and resets
   * Day(s) to run twofers
   * Categories to select songs
   * Percentage weights for list of categories
   * Rule selection for list of categories
   * PAL id for automated schedule highlighting
   * Wait count
   * Maximum failure count before giving up
   * Failure wait count
   * Minimum songs available for twofer selection
 Schedule this PAL with SAMs Event Scheduler (ES):
   * Switch to a desktop with the ES visible
     OR
     Make the ES visible by clicking the 'Window' menu item and selecting 'Event Scheduler'
   * Click '+' (Add new scheduled event)
   * Enter a name such as 'Twofers'
   * 'Event action' tab:
     * Under 'Action' click 'Execute PAL script'
     * In the 'PAL Script' section, click the folder icon and navigate to this script
   * 'Scheduled times' tab:
     * For a one time event:
       * Select the 'Execute one' button
       * Adjust the date/time
       * Click '+ Add'
       * Repeat as necessary for extra one time events
     * For recurring events:
       * Select the 'Execute every' button
       * Adjust date/time
       * Click '+ Add'
   * Save settings by clicking the 'File' menu item and selecting 'Save Configuration'
 For my station, this PAL runs at 12:01AM every day
 To handle requests as twofers, see 'Categories Processing' PAL
 Show your support for the effort, see [url]http://www.festerhead.com/forums/viewtopic.php?t=4[/url]
 Mahalo for your kokua
 WARNING!
 IF YOU DON'T CONFIGURE THE SCRIPT, DON'T EXPECT IT TO WORK PROPERLY!
 I built this PAL for my station using my station configuration
 Your results and mileage may vary
 I suggest running the PAL in debugOn mode for a couple days to see if it needs tweaking
 See below for change log
}
// Make the PAL run fast!
PAL.LockExecution;
{
 **************************
 * START OF CONFIGURABLES *
 **************************
}
{
 Run in debug mode?
 This will write to the screen without any queue interaction
 Useful for testing the script settings
 Turns on memory leak warning
}
var debugOn : Boolean = false;
{
 Enable memory leak warning?
 Automatically enabled if debugOn is true
 Stoping then starting a running script will give false memory leak warnings.
 To stop/start do one of the following:
   1.
     a. Add some spaces to the end of a line
     b. Save the script
     c. Compile the script
     d. Run the script
   2.
     a. Remove the script
     b. Add the script
     c. Compile the script
     d. Run the script
}
var memoryLeakAlwaysOn : Boolean = false;
{
 Define automatic show updating values
}
var text1Update : String = 'Now playing: Twofers!';
var text2Update : String = 'Back-to-back songs by your favorite artists';
var text1Reset : String = 'Now playing: Regular schedule';
var text2Reset : String = 'Normal rotation and listener requests';
{
 What days do you want the Twofers played?
 If debugOn is true, then we run no matter what day is here
}
var theDays : Array of Integer = [Tuesday];
{
 Define the categories to pick song candidates from
 See below for setting thePercentages
}
var theCategories : Array of String = ['Tracks', 'Classics', 'Texas', 'CDX', 'New Releases'];
{
 Define the percentages of each category
 These need to add to 100.  Use a calculator if necessary
 The order here corresponds to the order of theCategories above
}
var thePercentages : Array of Integer = [20, 10, 30, 10, 30];
{
 Define the choosing methods of each category
 The order here corresponds to the order of theCategories above
}
var theChoosers : Array of Integer = [smRandom, smRandom, smRandom, smRandom, smRandom];
{
 Define the enforcing methods of each category
 The order here corresponds to the order of theCategories above
}
var theEnforcers : Array of Boolean = [EnforceRules, EnforceRules, EnforceRules, EnforceRules, EnforceRules];
{
 Database table name for logging show history
 Debug table automatically appended with '_debug'
}
var tableName : String = 'twofer';
{
 Define the PAL ids for automated schedule page highlighting
 Leave this alone if you don't have automated schedule page highlighting
}
var idThisPAL : Integer = 1;
var idResetPAL : Integer = 0;
{
 How many songs to wait before running the script again?
 Check your SAM configuration for your setting
 If you're not sure what to do here, leave this alone
}
var waitCount : Integer = PlaylistRules.MinQueueSize + 1;
{
 Use PAL.WaitForQueue instead of PAL.WaitForPlay?
 If there are other regularly scheduled jingles, ads, and/or what-nots the queue could fill up with a lot of twofers if we use PAL.WaitForPlay
 In my view, this is unacceptable
 Feel free to set to false to use PAL.WaitForPlay and have fun
 Watch your queue
 Automatically switched to false if debugOn is true
}
var useWaitForQueue : Boolean = true;
{
 Maximum times the script can fail to get a twofer before giving up
 If gives up, it'll add the singleton song candidate
 Don't set this too high
 This is to prevent a runaway PAL script.
}
var maxFailures : Integer = 5;
{
 How many songs to wait if we fail to generate a twofer before restarting?
}
var failureCountWait : Integer = 1;
{
 Maximum candidate matches required to consider a song as twoferable
 After choosing a candidate, there needs to be this number of other songs to choose from
 Don't set this too high or less than one
}
var minimumAvailable : Integer = 10;
{
 Is this cool or what?
 var cool : Boolean = true;
}
{
 ************************
 * END OF CONFIGURABLES *
 ************************
}
// IF YOU EDIT BELOW HERE, MAKE DARN SURE YOU KNOW WHAT'S GOING ON
// Declare variables
var theCandidate : TSongInfo;
var theSongChooser, currentShow : TDataSet;
// Declare and initialize stuff
var randomInteger : Integer = 0;
var song1 : Integer = -1;
var song2 : Integer = -1;
var counter : Integer = 0;
var bad : Boolean = false;
var good : Boolean = false;
var runNow : Boolean = false;
var theCategory : String = '';
var theChooser : Integer = smRandom;
var theEnforcer : Boolean = EnforceRules;
var theSQL : String = '';
var looper : Integer = 0;
var accumulator : Integer = 0;
var found : Boolean = false;
// Randomize!
Randomize;
if (debugOn or memoryLeakAlwaysOn) then
 begin
   PAL.MemoryLeakWarning := true;
   WriteLn('Memory leak warning is ON');
 end;
if (debugOn) then
 begin
   useWaitForQueue := false;
   WriteLn('WaitForPlay is ON');
 end;
// Determine if we runNow.  Loop through theDays and find the one to use
for looper := 0 to theDays.length-1 do
 begin
   // Run now?
   if ((DayOfWeek(Now) = theDays[looper]) and (not runNow)) then
     begin
       runNow := true;
       PAL.Loop := true;
     end;
 end;
if (debugOn) then
 begin
   if (PAL.GetLoop) then
     begin
       WriteLn('PAL.Loop := true');
     end
   else
     begin
       WriteLn('PAL.Loop := false');
     end;
 end;
if (not runNow) then
 begin
   PAL.Loop := false;
 end;
while ((counter   begin
   // Setup automatic show updating
   if (not debugOn) then
     begin
       // Create the table if it doesn't already exist
       ExecSQL('CREATE TABLE IF NOT EXISTS currentshow ' +
               '(id MEDIUMINT(9), text1 VARCHAR(255), text2 VARCHAR(255))', []);
       currentShow := Query('SELECT COUNT(*) AS cnt FROM currentshow', [], true);
       // If no rows in currentshow, do an insert
       // Else, do an update
       if (currentShow['cnt'] = 0) then
         begin
           ExecSQL('INSERT INTO currentshow (id, text1, text2) ' +
                   'VALUES (' + IntToStr(idThisPAL) + ', ' + QuotedStr(text1Update) + ', ' +
                                QuotedStr(text2Update) + ')', []);
         end
       else
         begin
           ExecSQL('UPDATE currentshow SET id = ' + IntToStr(idThisPAL), []);
           ExecSQL('UPDATE currentshow SET text1 = ' + QuotedStr(text1Update), []);
           ExecSQL('UPDATE currentshow SET text2 = ' + QuotedStr(text2Update), []);
         end;
     end;
   // Increment the number of times run
   counter := counter + 1;
   if (debugOn) then
     begin
       WriteLn('Counter = ' + IntToStr(counter));
     end;
   // Generate a random number
   randomInteger := RandomInt(100) + 1;
   if (debugOn) then
     begin
       WriteLn('Random number = ' + IntToStr(randomInteger));
     end;
   found := false;
   // Select a category
   // Loop through theCategories and find the one to use
   for looper := 0 to theCategories.length-1 do
     begin
       // Accumulate the accumulator
       accumulator := accumulator + thePercentages[looper];
       // This the one to use?
       if ((randomInteger           begin
           theCategory := theCategories[looper];
           theChooser := theChoosers[looper];
           theEnforcer := theEnforcers[looper];
           found := true;
         end;
     end;
   // Grab a candidate
   theCandidate := CAT[theCategory].ChooseSong(theChooser, theEnforcer);
   if (theCandidate  nil) then
     begin
       if (debugOn) then
         begin
           WriteLn('Potential candidate: ' + theCandidate['artist'] + ' --- ' + theCandidate['title']);
         end;
       song1 := theCandidate['id'];
       // Do the query
       theSongChooser := Query('SELECT COUNT(*) AS cnt ' +
                               'FROM songlist ' +
                               'WHERE id  ' + IntToStr(theCandidate['id']) + ' ' +
                               'AND title  ' + QuotedStr(theCandidate['title']) + ' ' +
                               'AND artist = ' + QuotedStr(theCandidate['artist']) + ' ' +
                               'AND date_played                                 'AND songtype = ''S''', [], true);
       if (debugOn) then
         begin
           WriteLn('There are ' + IntToStr(theSongChooser['cnt']) + ' songs to choose from');
         end;
       // Validate the count
       // If less than minimumAvailable songs to choose from, candidate is a failure
       if (theSongChooser['cnt']           begin
           if (debugOn) then
             begin
               WriteLn('Less than ' + IntToStr(minimumAvailable) + ' songs to choose from!  Counter = ' + IntToStr(counter) + '.  Starting over...');
             end;
           // Not good, but haven't reached maximum failure count
           if (counter >= maxFailures) then
             begin
               // Failed to generate a twofer
               bad := true;
               WriteLn('Max failures reached!  Counter = ' + IntToStr(counter) + '.  Adding candidate and waiting ' + IntToStr(failureCountWait) + ' song(s)...');
               // Add the candidate
               if (not debugOn) then
                 begin
                   Queue.Add(theCandidate, ipBottom);
                 end;
             end;
         end
       // We have more than one song to choose from.  Candidate is a success.
       else
         begin
           good := true;
           // Do the query
           theSongChooser := Query('SELECT artist, title, filename, id ' +
                                   'FROM songlist ' +
                                   'WHERE id  ' + IntToStr(theCandidate['id']) + ' ' +
                                   'AND title  ' + QuotedStr(theCandidate['title']) + ' ' +
                                   'AND artist = ' + QuotedStr(theCandidate['artist']) + ' ' +
                                   'AND date_played                                     'AND songtype = ''S'' ' +
                                   'ORDER BY RAND() LIMIT 1', [], true);
           // Grab the song id
           song2 := theSongChooser['id'];
           // Put candidate and random song in queue bottom
           if (not debugOn) then
             begin
               Queue.Add(theCandidate, ipBottom);
               Queue.AddFile(theSongChooser['filename'], ipBottom);
             end;
           // Log the twofer to the screen
           WriteLn('Added: ' + QuotedStr(theCandidate['artist']) + ' --- ' + QuotedStr(theCandidate['title']));
           WriteLn('Added: ' + QuotedStr(theSongChooser['artist']) + ' --- ' + QuotedStr(theSongChooser['title']));
           // Keeping separate just in case we want to log more
           // stuff when in debugOn mode
           if (debugOn) then
             begin
               // Create the table if it doesn't already exist
               ExecSQL('CREATE TABLE IF NOT EXISTS ' + tableName + '_debug ' +
                       '(id MEDIUMINT(9) AUTO_INCREMENT PRIMARY KEY, ' +
                       'date DATETIME, ' +
                       'song1 MEDIUMINT(9), ' +
                       'song2 MEDIUMINT(9), ' +
                       'counter MEDIUMINT(9))', []);
               ExecSQL('INSERT INTO ' + tableName + '_debug (date, song1, song2, counter) VALUES (''' +
                       FormatDateTime('yyyy-mm-dd hh:mm:ss', Now) + ''', ' +
                       IntToStr(song1) + ', ' +
                       IntToStr(song2) + ', ' +
                       IntToStr(counter) + ')', []);
             end
           else
             begin
               // Create the table if it doesn't already exist
               ExecSQL('CREATE TABLE IF NOT EXISTS ' + tableName + ' ' +
                       '(id MEDIUMINT(9) AUTO_INCREMENT PRIMARY KEY, ' +
                       'date DATETIME, ' +
                       'song1 MEDIUMINT(9), ' +
                       'song2 MEDIUMINT(9), ' +
                       'counter MEDIUMINT(9))', []);
               ExecSQL('INSERT INTO ' + tableName + ' (date, song1, song2, counter) VALUES (''' +
                       FormatDateTime('yyyy-mm-dd hh:mm:ss', Now) + ''', ' +
                       IntToStr(song1) + ', ' +
                       IntToStr(song2) + ', ' +
                       IntToStr(counter) + ')', []);
             end;
         end;
     end
   else
     begin
       WriteLn('NIL candidate.  That sucks.  Running again...');
     end;
 end;
// Stop the PAL from running fast!
PAL.UnlockExecution;
// Do an action based on a bad or good twofer generation
// Yes these are separate if-then statements.  Deal with it.
if (bad and runNow) then
 begin
   if (debugOn) then
     begin
       WriteLn('Waiting for SAM to play ' + IntToStr(failureCountWait) + ' songs');
     end;
   PAL.WaitForPlayCount(failureCountWait);
 end;
if (good and runNow) then
 begin
   if (useWaitForQueue) then
     begin
       if (debugOn) then
         begin
           WriteLn('Waiting for queue to reach ' + IntToStr(waitCount) + ' songs');
         end;
       PAL.WaitForQueue(waitCount);
     end
   else
     begin
       if (debugOn) then
         begin
           WriteLn('Waiting for SAM to play ' + IntToStr(waitCount) + ' songs');
         end;
       PAL.WaitForPlayCount(waitCount);
     end;
 end;
if (runNow and (not debugOn)) then
 begin
   // Reset the show
   ExecSQL('UPDATE currentshow SET id = ' + IntToStr(idResetPAL), []);
   ExecSQL('UPDATE currentshow SET text1 = ' + QuotedStr(text1Reset), []);
   ExecSQL('UPDATE currentshow SET text2 = ' + QuotedStr(text2Reset), []);
 end;
// Be nice...  Free up the data structures
theSongChooser.Free;
theCandidate.Free;
currentShow.Free;
Queue.Free;
CAT.Free;

Spacial SVS Support Team

http://support.spacialaudio.com/forums/

Get help with PAL Scripts at http://www.palscripts.com

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...