Product SiteDocumentation Site

11.4.5. Creating Ten Pseudo-Random Tones

  1. We'll start again with something simple, that we know how to do.
    {
       SinOsc.ar();
    }.play;
    
  2. We already know that we want this to produce stereo output, and we already know that we're going to be using enough SinOsc's that we'll need to reduce "mul." Keeping in mind that there will be ten pitches, and two SinOsc's for each of them, set both of those things now, keeping just one pitch for now.
  3. The first challenge is to implement pseudo-randomness. We'll use the number.rand function to generate a pseudo-random number (integer, actually), but if run as 50.rand, we will get a result between 0 and 50. As a frequency, this is not useful: most audio equipment cannot produce pitches below 20 Hz, and many people have problems hearing very low frequencies. This means that we'll need to add a value to .rand's output (like 100 + 50.rand, which will yield an integer between 100 and 150). I decided to go with a value between 200 Hz and 800 Hz instead, largely because I felt like it. Try setting the freq with the .rand call.
  4. I hope you didn't end up with two different frequencies! If you did, you'll need to use a variable to temporarily store the pseduo-random frequency, so that both sides can use it.
  5. Now we need to make ten of these, so copy-and-paste until there are ten different stereo pitches at once.
    {
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
       var frequency = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency, mul:0.01 ), SinOsc.ar( freq:frequency, mul:0.01 ) ]
    }.play;
    
  6. It doesn't work: you'll also have to rename your frequency-setting variable each time.
    {
       var frequency1 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency1, mul:0.01 ), SinOsc.ar( freq:frequency1, mul:0.01 ) ]
       var frequency2 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency2, mul:0.01 ), SinOsc.ar( freq:frequency2, mul:0.01 ) ]
       var frequency3 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency3, mul:0.01 ), SinOsc.ar( freq:frequency3, mul:0.01 ) ]
       var frequency4 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency4, mul:0.01 ), SinOsc.ar( freq:frequency4, mul:0.01 ) ]
       var frequency5 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency5, mul:0.01 ), SinOsc.ar( freq:frequency5, mul:0.01 ) ]
       var frequency6 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency6, mul:0.01 ), SinOsc.ar( freq:frequency6, mul:0.01 ) ]
       var frequency7 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency7, mul:0.01 ), SinOsc.ar( freq:frequency7, mul:0.01 ) ]
       var frequency8 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency8, mul:0.01 ), SinOsc.ar( freq:frequency8, mul:0.01 ) ]
       var frequency9 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency9, mul:0.01 ), SinOsc.ar( freq:frequency9, mul:0.01 ) ]
       var frequency0 = 200 + 600.rand;
       [ SinOsc.ar( freq:frequency0, mul:0.01 ), SinOsc.ar( freq:frequency0, mul:0.01 ) ]
    }.play;
    
  7. It still doesn't work! The error given in the "SuperCollider output" window is not easy to understand, but it means "You have to put all of your variable declarations before everything else."
    {
       var frequency1 = 200 + 600.rand;
       var frequency2 = 200 + 600.rand;
       var frequency3 = 200 + 600.rand;
       var frequency4 = 200 + 600.rand;
       var frequency5 = 200 + 600.rand;
       var frequency6 = 200 + 600.rand;
       var frequency7 = 200 + 600.rand;
       var frequency8 = 200 + 600.rand;
       var frequency9 = 200 + 600.rand;
       var frequency0 = 200 + 600.rand;
    
       [ SinOsc.ar( freq:frequency1, mul:0.01 ), SinOsc.ar( freq:frequency1, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency2, mul:0.01 ), SinOsc.ar( freq:frequency2, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency3, mul:0.01 ), SinOsc.ar( freq:frequency3, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency4, mul:0.01 ), SinOsc.ar( freq:frequency4, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency5, mul:0.01 ), SinOsc.ar( freq:frequency5, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency6, mul:0.01 ), SinOsc.ar( freq:frequency6, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency7, mul:0.01 ), SinOsc.ar( freq:frequency7, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency8, mul:0.01 ), SinOsc.ar( freq:frequency8, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency9, mul:0.01 ), SinOsc.ar( freq:frequency9, mul:0.01 ) ]
       [ SinOsc.ar( freq:frequency0, mul:0.01 ), SinOsc.ar( freq:frequency0, mul:0.01 ) ]
    }.play;
    
  8. It still doesn't work! SuperCollider is confused because I was been lazy and didn't include enough semicolons. The error we get is, "Index not an Integer," which is a clue as to what SuperCollider is trying to do (but it's irrelevant). The real problem is that SuperCollider interprets our ten stereo arrays as all being part of the same statement. We don't want them to be the same statement, however, because we want ten different stereo arrays to be played. Fix this problem by putting a semicolon at the end of each stereo array. You do not need to include one at the end of the last statement, because SuperCollider assumes the end of the statement when it encounters a } (end-of-function marker) after it. Since we're still building our code, we might move these around or add something aftwards, so it's better to include a semicolon at the end of each stereo array.
  9. Now the file plays successfully, but with a disappointing result. If you can't already see the problem, try to think of it before continuing to read.
  10. Only one SinOsc array gets played, and it's the last one. This is because the last statement is returned by the function that ends at } and it is that result which gets sent to the following .play
  11. To fix this, and ensure that all of the stereo arrays are played, you should remove the .play from the end of the function, and add a .play to each stereo array statement. You end up with
    {
       var frequency1 = 200 + 600.rand;
       var frequency2 = 200 + 600.rand;
       var frequency3 = 200 + 600.rand;
       var frequency4 = 200 + 600.rand;
       var frequency5 = 200 + 600.rand;
       var frequency6 = 200 + 600.rand;
       var frequency7 = 200 + 600.rand;
       var frequency8 = 200 + 600.rand;
       var frequency9 = 200 + 600.rand;
       var frequency0 = 200 + 600.rand;
    
       [ SinOsc.ar( freq:frequency1, mul:0.01 ), SinOsc.ar( freq:frequency1, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency2, mul:0.01 ), SinOsc.ar( freq:frequency2, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency3, mul:0.01 ), SinOsc.ar( freq:frequency3, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency4, mul:0.01 ), SinOsc.ar( freq:frequency4, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency5, mul:0.01 ), SinOsc.ar( freq:frequency5, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency6, mul:0.01 ), SinOsc.ar( freq:frequency6, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency7, mul:0.01 ), SinOsc.ar( freq:frequency7, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency8, mul:0.01 ), SinOsc.ar( freq:frequency8, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency9, mul:0.01 ), SinOsc.ar( freq:frequency9, mul:0.01 ) ].play;
       [ SinOsc.ar( freq:frequency0, mul:0.01 ), SinOsc.ar( freq:frequency0, mul:0.01 ) ].play;
    }
    
  12. When you execute this, no sound is produced, but SuperCollider outputs "a Function." Can you think of why this happens? It's because you wrote a function, but never told SuperCollider to evaluate it! At the end of execution, SuperCollider just throws away the function, because it's never used. This is the same thing that happened to the first nine stereo arrays - they were created, but you never said to do anything with them, so they were just thrown out. We need to execute the function. Because it doesn't produce a UGen, we can't use "play," so we have to use "value" instead. You can choose to do either of these:
    { ... }.value;
    or
    var myFunction = { ... };
    myFunction.value;
    
  13. This gives us yet another error, as if we can't play the stereo arrays! In fact, we can't - and we didn't do it in the first part, either. We play'ed the result of returning a stereo array from a function. The subtle difference isn't important yet - we're just trying to make this work! Use { and } to build a function for .play to .play
  14. Now make the correction nine more times.
  15. When you play execute the resulting code, you probably get something that sounds quite "space-age." Execute it a few times, to see the kind of results you get.