0

I'm currently making an app that plays a song. I wanted to play a random song each a button is clicked. I currently have :

-(IBAction)currentMusic:(id)sender {
NSLog(@"Random Music");
int MusicRandom = arc4random_uniform(2);
switch (MusicRandom) {
    case 0:
        [audioPlayerN stop];
        [audioPlayer play];
        break;
    case 1:
        [audioPlayer stop];
        [audioPlayerN play];
        break;

but I already tried :

- (IBAction)randomMusic:(id)sender {
NSLog(@"Random Music");




NSMutableArray * numberWithSet = [[NSMutableArray alloc]initWithCapacity:3];

int randomnumber = (arc4random() % 2)+1;



while ([numberWithSet containsObject:[NSNumber numberWithInt:randomnumber]])
{
    NSLog(@"Yes, they are the same");
    randomnumber = (arc4random() % 2)+1;
}

[numberWithSet addObject:[NSNumber numberWithInt:randomnumber]];




NSLog(@"numberWithSet : %@ \n\n",numberWithSet);
switch (randomnumber) {
    case 1:
        [audioPlayerN stop];
        [audioPlayer play];
        NSLog(@"1");
        break;
    case 2:
        [audioPlayer stop];
        [audioPlayerN play];

        NSLog(@"2");
        break;
    default:
        break;

}
}

And all of them work, the thing is, even though I will add more songs, they repeat. I wanted a random code that would not repeat. Like plays song 1, song 2, song 3, song 4 and song 5 randomly, and when plays all of them restarts. Like a Loop. But my current code is like song 1, song 1, song 2, song 1, song 2, and so on...Is there any way to not repeat the songs except for when all of them have been played? Thank you very much.

Mykod
  • 587
  • 1
  • 5
  • 16

2 Answers2

2

You want to generate a random permutation.

Option 1

Hat tip @Alexander for this simpler approach...

if(![songsToPlay count])
    [songsToPlay addObjectsFromArray:songList];

int index = arc4random_uniform([songsToPlay count]);
playSong(songsToPlay[index]);
[songsToPlay removeObjectAtIndex:index];

Quick explanation:

  • NSMutableArray *songsToPlay: Stores the list of songs that haven't been played yet this round. Contents could be of type:
    • NSString, storing a filename
    • NSNumber, storing a song index
  • NSArray *songList: Stores the list of all songs you want to play. Contents should be of same type as songsToPlay. Could also be a NSMutableArray.
  • playSong(id songToPlay): Stops any current songs and plays songToPlay. You'll need to write this function, since it depends on your implementation.

Option 2

Using Knuth shuffles is another approach:

unsigned permute(unsigned permutation[], unsigned n)
{
    unsigned i;
    for (i = 0; i < n; i++) {
        unsigned j = arc4random_uniform(i);
        permutation[i] = permutation[j];
        permutation[j] = i;
    }
}

Then call the function every time you want to shuffle the songs:

int permutation[NUM_SONGS];

// I'm using a while loop just to demonstrate the idea.
// You'll need to adapt the code to track where you are
// in the permutation between button presses.
while(true) {
    for(int i = 0; i < NUM_SONGS; ++i)
        permutation[i] = i;

    permute(permutation, NUM_SONGS);

    for(int i = 0; i < NUM_SONGS; ++i) {
        int songNum = permutation[i];
        playSong(songNum);
    }
    waitForButtonPress();
}
godel9
  • 7,340
  • 1
  • 33
  • 53
  • I'm really sorry but I don't quite understand. Is there any advantage in any of the approaches over the other? Also, I'll probably use the first one as it seems easier, but still I don't understand what is the SongsToPlay and songList. Are they NSMutableArrays? Could you please, please give me a more detailed explanation? Thank you so much for your patience! – Mykod Nov 04 '13 at 14:10
  • @Mykod I've updated the answer with an explanation of what all the variables and functions mean. – godel9 Nov 04 '13 at 14:28
  • @Mykod To answer your first question, you pretty much want to use the the first approach because of its simplicity. – godel9 Nov 04 '13 at 14:46
1

First of all, you're only hearing 2 songs because your randomnumber generation is limited to only 2 values.

For the other problem you can create a mutable array with randomly placed tracks and remove each played element. When the count reaches 0 just start playing tracks in random order.

Alexander
  • 8,117
  • 1
  • 35
  • 46