Very rough first start, not even everything added
This commit is contained in:
commit
af3619d4fa
88 changed files with 24251 additions and 0 deletions
430
PlaylistBroadcaster.tproj/PlaylistPicker.cpp
Normal file
430
PlaylistBroadcaster.tproj/PlaylistPicker.cpp
Normal file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "SafeStdLib.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "MyAssert.h"
|
||||
#include "OS.h"
|
||||
|
||||
|
||||
#include "PlaylistPicker.h"
|
||||
|
||||
/*
|
||||
PlaylistPicker has 3 modes
|
||||
- sequential looping through the items in the play list(s)
|
||||
in the order they are entered.
|
||||
|
||||
- above w/ looping
|
||||
|
||||
- weighted picking "randomly" from weighted buckets
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
PlaylistPicker::PlaylistPicker( UInt32 numBuckets, UInt32 numNoRepeats )
|
||||
{
|
||||
// weighted random ctor
|
||||
|
||||
mFirstElement = NULL;
|
||||
mNumToPickFrom = 0;
|
||||
mBuckets = numBuckets;
|
||||
mIsSequentialPicker = false;
|
||||
mRecentMoviesListSize = numNoRepeats;
|
||||
|
||||
/* changed by emil@popwire.com (see relaod.txt for info) */
|
||||
mRemoveFlag = false;
|
||||
mStopFlag = false;
|
||||
/* ***************************************************** */
|
||||
mLastResult = (UInt32) OS::Milliseconds();
|
||||
|
||||
mPickCounts = new SInt32[numBuckets];
|
||||
UInt32 x;
|
||||
|
||||
for ( x = 0; x < mBuckets; x++ )
|
||||
{ mPickCounts[x] = 0;
|
||||
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
|
||||
Assert( mElementLists[x] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
mUsedElements = new NoRepeat( numNoRepeats );
|
||||
|
||||
Assert( mUsedElements );
|
||||
}
|
||||
|
||||
PlaylistPicker::PlaylistPicker(bool doLoop)
|
||||
{
|
||||
// sequential ctor
|
||||
|
||||
mFirstElement = NULL;
|
||||
mIsSequentialLooping = doLoop;
|
||||
|
||||
mIsSequentialPicker = true;
|
||||
mWhichSequentialBucket = 0;
|
||||
mRecentMoviesListSize = 0;
|
||||
|
||||
mNumToPickFrom = 0;
|
||||
mBuckets = 2; // alternating used/remaining pick buckets
|
||||
/* changed by emil@popwire.com (see relaod.txt for info) */
|
||||
mRemoveFlag = false;
|
||||
mStopFlag = false;
|
||||
fLastPick = NULL;
|
||||
/* ***************************************************** */
|
||||
|
||||
|
||||
mPickCounts = new SInt32[mBuckets];
|
||||
|
||||
|
||||
UInt32 bucketIndex;
|
||||
|
||||
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
|
||||
{
|
||||
mPickCounts[bucketIndex] = 0;
|
||||
mElementLists[bucketIndex] = new PLDoubleLinkedList<SimplePlayListElement>;
|
||||
Assert( mElementLists[bucketIndex] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
mUsedElements = NULL;
|
||||
|
||||
}
|
||||
|
||||
PlaylistPicker::~PlaylistPicker()
|
||||
{
|
||||
UInt32 bucketIndex;
|
||||
|
||||
delete mUsedElements;
|
||||
|
||||
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
|
||||
{
|
||||
delete mElementLists[bucketIndex] ;
|
||||
|
||||
}
|
||||
|
||||
delete [] mPickCounts;
|
||||
}
|
||||
|
||||
|
||||
UInt32 PlaylistPicker::Random()
|
||||
{
|
||||
UInt32 seed = 1664525L * mLastResult + 1013904223L; //1013904223 is prime .. Knuth D.E.
|
||||
::srand( seed );
|
||||
|
||||
UInt32 result = ::rand();
|
||||
|
||||
mLastResult = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char* PlaylistPicker::PickOne()
|
||||
{
|
||||
|
||||
char* foundName = NULL; // pointer to name of pick we find, caller deletes.
|
||||
|
||||
|
||||
if ( mIsSequentialPicker )
|
||||
{
|
||||
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() == 0 && mIsSequentialLooping )
|
||||
{ // ran out of items switch to other list.
|
||||
if ( mWhichSequentialBucket == 0 )
|
||||
mWhichSequentialBucket = 1;
|
||||
else
|
||||
mWhichSequentialBucket = 0;
|
||||
|
||||
}
|
||||
|
||||
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() > 0 )
|
||||
{
|
||||
PLDoubleLinkedListNode<SimplePlayListElement>* node;
|
||||
|
||||
|
||||
node = mElementLists[mWhichSequentialBucket]->GetFirst();
|
||||
|
||||
Assert( node );
|
||||
|
||||
int nameLen = ::strlen( node->fElement->mElementName );
|
||||
|
||||
foundName = new char[ nameLen +1 ];
|
||||
|
||||
Assert( foundName );
|
||||
|
||||
if ( foundName )
|
||||
{
|
||||
int usedBucketIndex;
|
||||
|
||||
::strcpy( foundName, node->fElement->mElementName );
|
||||
|
||||
// take him out of the bucket since he's now in play
|
||||
mElementLists[mWhichSequentialBucket]->RemoveNode( node );
|
||||
|
||||
|
||||
if ( mWhichSequentialBucket == 0 )
|
||||
usedBucketIndex = 1;
|
||||
else
|
||||
usedBucketIndex = 0;
|
||||
|
||||
/* changed by emil@popwire.com (see relaod.txt for info) */
|
||||
if(!mRemoveFlag)
|
||||
/* ***************************************************** */
|
||||
mElementLists[usedBucketIndex]->AddNodeToTail( node );
|
||||
/* changed by emil@popwire.com (see relaod.txt for info) */
|
||||
else
|
||||
mNumToPickFrom--;
|
||||
/* ***************************************************** */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SInt32 bucketIndex;
|
||||
UInt32 minimumBucket = 0;
|
||||
UInt32 avaiableToPick;
|
||||
UInt32 theOneToPick;
|
||||
SInt32 topBucket;
|
||||
|
||||
|
||||
// find the highest bucket with some elements.
|
||||
bucketIndex = this->GetNumBuckets() - 1;
|
||||
|
||||
while ( bucketIndex >= 0 && mElementLists[bucketIndex]->GetNumNodes() == 0 )
|
||||
{
|
||||
bucketIndex--;
|
||||
}
|
||||
|
||||
|
||||
// adjust to 1 based so we can use MOD
|
||||
topBucket = bucketIndex + 1;
|
||||
|
||||
//qtss_printf( "topBucket %li \n", topBucket );
|
||||
|
||||
if (topBucket > 0)
|
||||
minimumBucket = this->Random() % topBucket; // find our minimum bucket
|
||||
|
||||
//qtss_printf( "minimumBucket %li \n", minimumBucket );
|
||||
|
||||
// pick randomly from the movies in this and higher buckets
|
||||
// sum the available elements, then pick randomly from them.
|
||||
|
||||
avaiableToPick = 0;
|
||||
|
||||
bucketIndex = minimumBucket;
|
||||
|
||||
while ( bucketIndex < topBucket )
|
||||
{
|
||||
avaiableToPick += mElementLists[bucketIndex]->GetNumNodes();
|
||||
|
||||
bucketIndex++;
|
||||
}
|
||||
|
||||
//qtss_printf( "avaiableToPick %li \n", avaiableToPick );
|
||||
|
||||
// was anyone left??
|
||||
|
||||
if ( avaiableToPick )
|
||||
{
|
||||
theOneToPick = this->Random() % avaiableToPick;
|
||||
//qtss_printf( "theOneToPick %li \n", theOneToPick );
|
||||
|
||||
// now walk through the lists unitl we get to the list
|
||||
// that contains our pick, then pick that one.
|
||||
bucketIndex = minimumBucket;
|
||||
|
||||
while ( bucketIndex < topBucket && foundName == NULL )
|
||||
{
|
||||
|
||||
//qtss_printf( "theOneToPick %li, index %li numelements %li\n", theOneToPick , bucketIndex, mElementLists[bucketIndex]->GetNumNodes());
|
||||
|
||||
if ( theOneToPick >= mElementLists[bucketIndex]->GetNumNodes() )
|
||||
theOneToPick -= mElementLists[bucketIndex]->GetNumNodes();
|
||||
else
|
||||
{ //qtss_printf( "will pick theOneToPick %li, index %li \n", theOneToPick, bucketIndex);
|
||||
foundName = this->PickFromList( mElementLists[bucketIndex], theOneToPick );
|
||||
if ( foundName )
|
||||
mPickCounts[bucketIndex]++;
|
||||
}
|
||||
|
||||
bucketIndex++;
|
||||
}
|
||||
|
||||
// we messed up if we don't have a name at this point.
|
||||
Assert( foundName );
|
||||
}
|
||||
}
|
||||
|
||||
fLastPick = foundName;
|
||||
return foundName;
|
||||
|
||||
}
|
||||
|
||||
void PlaylistPicker::CleanList()
|
||||
{
|
||||
|
||||
mFirstElement = NULL;
|
||||
mNumToPickFrom = 0;
|
||||
|
||||
delete mUsedElements;
|
||||
mUsedElements = new NoRepeat( mRecentMoviesListSize );
|
||||
|
||||
delete [] mPickCounts;
|
||||
mPickCounts = new SInt32[mBuckets];
|
||||
|
||||
UInt32 x;
|
||||
for ( x = 0; x < mBuckets; x++ )
|
||||
{
|
||||
mPickCounts[x] = 0;
|
||||
delete mElementLists[x];
|
||||
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
|
||||
Assert( mElementLists[x] );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
char* PlaylistPicker::PickFromList( PLDoubleLinkedList<SimplePlayListElement>* list, UInt32 elementIndex )
|
||||
{
|
||||
PLDoubleLinkedListNode<SimplePlayListElement>* plNode;
|
||||
char* foundName = NULL;
|
||||
|
||||
|
||||
plNode = list->GetNthNode( elementIndex );
|
||||
|
||||
if ( plNode )
|
||||
{
|
||||
int nameLen = ::strlen(plNode->fElement->mElementName );
|
||||
|
||||
foundName = new char[ nameLen +1 ];
|
||||
|
||||
Assert( foundName );
|
||||
|
||||
if ( foundName )
|
||||
{
|
||||
::strcpy( foundName, plNode->fElement->mElementName );
|
||||
|
||||
// take him out of the bucket since he's now in play
|
||||
list->RemoveNode( plNode );
|
||||
|
||||
mNumToPickFrom--;
|
||||
|
||||
// add him to our used list, and possibly
|
||||
// get an older one to put back into play
|
||||
PLDoubleLinkedListNode<SimplePlayListElement>* recycleNode = mUsedElements->AddToList( plNode );
|
||||
|
||||
// if we got an old one to recycle, do so.
|
||||
if ( recycleNode )
|
||||
this->AddNode( recycleNode );
|
||||
}
|
||||
}
|
||||
|
||||
return foundName;
|
||||
|
||||
}
|
||||
|
||||
bool PlaylistPicker::AddToList( const char* name, int weight )
|
||||
{
|
||||
bool addedSuccesfully;
|
||||
PLDoubleLinkedListNode<SimplePlayListElement>* node;
|
||||
SimplePlayListElement* element;
|
||||
|
||||
|
||||
node = NULL;
|
||||
addedSuccesfully = false;
|
||||
element = new SimplePlayListElement(name);
|
||||
if (mFirstElement == NULL)
|
||||
mFirstElement = element->mElementName;
|
||||
|
||||
Assert( element );
|
||||
|
||||
|
||||
if ( element )
|
||||
{ element->mElementWeight = weight;
|
||||
node = new PLDoubleLinkedListNode<SimplePlayListElement>(element);
|
||||
|
||||
Assert( node );
|
||||
}
|
||||
|
||||
if ( node )
|
||||
addedSuccesfully = AddNode(node);
|
||||
|
||||
|
||||
return addedSuccesfully;
|
||||
}
|
||||
|
||||
bool PlaylistPicker::AddNode( PLDoubleLinkedListNode<SimplePlayListElement>* node )
|
||||
{
|
||||
bool addSucceeded = false;
|
||||
|
||||
|
||||
Assert( node );
|
||||
Assert( node->fElement );
|
||||
|
||||
|
||||
if ( mIsSequentialPicker ) // make picks in sequential order, not weighted random
|
||||
{
|
||||
// add all to bucket 0
|
||||
mElementLists[0]->AddNodeToTail( node );
|
||||
|
||||
addSucceeded = true;
|
||||
mNumToPickFrom++;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int weight;
|
||||
|
||||
weight = node->fElement->mElementWeight;
|
||||
|
||||
// weights are 1 based, correct to zero based for use as array myIndex
|
||||
weight--;
|
||||
|
||||
Assert( weight >= 0 );
|
||||
|
||||
Assert( (UInt32)weight < mBuckets );
|
||||
|
||||
if ( (UInt32)weight < mBuckets )
|
||||
{
|
||||
// the elements weighting defines the list it is in.
|
||||
mElementLists[weight]->AddNode( node );
|
||||
|
||||
addSucceeded = true;
|
||||
mNumToPickFrom++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return addSucceeded;
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue