New User attempting select BinaryResource at random


#1

Hi all,
I am looking for an elegant way to randomly select an audio file and play it … I plan to have 48 files … I assume it’s not a bad idea to include 48 mp3 files as binaries in a juce program.
I have this code which works but is very inelegant …
I am sure there is a better way to do this .
Any advice would be greatly appreciated thanks Sean

   {
       if (f == 0)
       {
           playfile(BinaryData::C5_mp3, BinaryData::C5_mp3Size);
       }
       if (f == 1)
       {
           playfile(BinaryData::C6_mp3, BinaryData::C6_mp3Size);
       }
   }
       
           

   void playfile(const void * sourceData, size_t sourceDataSize)
   {
   AudioFormatReader* reader = formatManager.createReaderFor( new MemoryInputStream(sourceData, sourceDataSize, false));
   if (reader != nullptr)
   {
       ScopedPointer<AudioFormatReaderSource> newSource = new AudioFormatReaderSource (reader, true);
       transportSource.setSource (newSource, 0, nullptr, reader->sampleRate);
       playButton.setEnabled (true);
       readerSource = newSource.release();
   }
   if (reader == nullptr)
   {
       playButton.setEnabled (false);
   }
   transportSource.setPosition (0.0);
   changeState (Starting);
   }
   

   
   void playButtonClicked()
   {
       int choice1 = rand() % 2;
       selectfile(choice1);
   } ```

#2

Get rid of the big if statement. ie. At start up, in a constructor somewhere, or even with static initialization, build an array of the mp3 resources, and access them via that data structure.


#3

Thanks so much CPR for your reply !
The if statement looked horrible to me!!
I thought about an array like that but
I don’t know enough about C++ or the class structures to understand how to initialize an array of those binarydata resources.
It looks to me like it should be an array of pointers to objects.
It would also be lovely if I could construct a method that passed an integer note name in as an argument and it found the binary resource and resource size …
That’s also a bit beyond my C++ and JUCE skills at this point …

Tonight I changed the random number generator to :
int choice1 = (rand() % 2);
It generates random numbers correctly in a simple program but within my code it seems to be just generating 1 each time.

I will keep battling away thanks so much for your input!
Best Sean


#4

Are you calling srand() too before each of those rand() calls? rand() is not supposed to be used that way, you should just call srand() once in your code and you can then make the rand() calls.

However, rand() would be best avoided these days. The implementations in the standard libraries are horrible and even more so when you limit the number range with something like % 2. At worst it might even happen it gets stuck outputting one number. So your problem probably is about calling srand() needlessly or about using rand()…

JUCE has its own Random class that is perhaps a bit better than the standard rand() implementations, but not much…If you can use C++11, that offers a good quality Mersenne Twister random generator as well as ways to limit and shape those numbers.

Here’s a video about why rand() is harmful. :slight_smile:


#5

Thanks so much Xenakios that’s an entertaining video!
I didn’t have much luck with that rand() function …
I wrote some code and compiled in clion and it seemed to do the trick in c++11 but inside juce it seemed to produce a 1 every time …
Don’t know why! I will look for an alternative thanks for your help !!
Sean


#6

For the record I used a Mersenne Twister which seems to work …
Thanks so much for your help !!

    {
        std::random_device device;
        std::mt19937 generator(device());
        std::uniform_int_distribution<int> distribution(0,1);
        

        int choice1 = distribution(generator);


        selectfile(choice1);
    } ```

#7

Please indent your code 4 spaces to make it readable in the forum! (or put triple-backticks around it)


#8

Thanks Jules ! I was wondering how to do that. I used triple back ticks.
Does it look OK now ?
Sean


#9

You are doing some heavy redundant work in that code…You shouldn’t really construct both the mt19937 and random_device each time when the function is called. You should rather put the mt19937 as a member variable in your class and init that once with the random device in your class constructor.


#10

Thanks Xenakios! This learner appreciates your sage advice !


#11

A mersenne twister is massive overkill if you’re just choosing a file to play! That stuff is really for cryptographic use - for something trivial like this the juce::Random class is a better choice.

And maybe look at the BinaryData class that’s generated - it provides a way to iterate the items in it by name, so you could write something that picks a random item without having to hardcode them all into a switch statement.


#12

I disagree. For starters, Mersenne Twister is not for cryptographic use since the sequence is predictable. (The std::random_device on the other hand is intended for that purpose.) Secondly, Mersenne Twister it is not that expensive and I was about to propose the Juce Random class should use that instead of the simple linear congruential implementation. But I guess you wouldn’t be that excited about doing that…


#13

Unfortunately, as with many things, the <random> header is not available when selecting older operating systems as deployment targets - so it can’t be used in the JUCE library code :frowning:


#14

Well yes, the Mersenne is somewhere in the middle between the juce very-fast-and-dumb one and some of the slow-but-crypto-safe algorithms. My point was really just that in this case it doesn’t matter at all what he uses, even rand() would do the job (but please don’t ever use it!!)


#15

Ah right… :unamused: Any plans for you guys to drop the Mac OS-X 10.6 support at some point? :wink:


#16

Thanks Jules et all ,
I am so ignorant that I couldn’t figure out how to implement the random class but got the Twister to work.
Can I use something like this to select BinaryData objects?
BinaryData::getNamedResource(BinaryData::namedResourceList[0])
As I learn C++ better and understand JUCE better I will figure it out on my own …


#17

Using the Juce Random object is pretty similar to how you would correctly use the standard library Mersenne Twister : have an instance of it as a member of your class and call nextInt(maxitems) when you need the random number. You could also call setSeedRandomly of the Random object in your class constructor to get a different random sequence each time your application runs.


#18

Thanks !!!


#19

I could be mistaken here but doesn’t the default constructor create the seed based on the time so will be different every time your app starts anyway?

There is also a static instance of this so you don’t need to create a Random object yourself. Simply call:
int randomNum = Random::getSystemRandom().nextInt (max);

We use that all the time and no one has ever complained about our sequences being too predictable…


#20

Yes I put this line into the code
int choice1 = Random::getSystemRandom().nextInt(2);
This seemed to generate either a 0 or a 1
This program doesn’t need to be lightweight …

I still need to figure out how to select a binary resource using an integer.