Product SiteDocumentation Site

11.4.9. Joining the Two Parts

Now it is time to join the two parts, and ensure a clean transition between them. My reasons for building the first part as a SynthDef, but the second part as a function are explained in the file. Additional reasons include my desire to illustrate the use of both possibilities, and because the second part stops itself (so it can be a function which is executed and forgotten), whereas the first part does not stop itself (so we'll need to hold onto the synth, to stop it ourselves).
  1. I copy-and-pasted both parts into a new file, leaving the other original code in tact, in case I want to build on them in the future. Be sure to copy over the var t_c = TempoClock.default; definition from the second part.
  2. By default, the two parts would both start playing at the same time (give it a try!) This isn't what we want, however, so you'll need to erase the "play" command from both parts' functions. We'll also need some way to refer to them, so declare the second part as a variable (I've used the name, "secondPart,"), but don't worry about the first part yet. Don't forget the semicolon at the end of the function declaration!
  3. To join the two parts, I'm going to use function that does all the scheduling. This is similar to a "main" function, which are used in most programming languages. Although they are optional in SuperCollider, it just makes sense to use one function that does all the scheduling, and nothing else: that way, when you have problems with the scheduling, or you want to make an adjustment or addition to the program, you can easily find the place where the scheduling happens. If your scheduling commands were spread out through the source file, it would be much more difficult to find and modify the scheduling commands.
  4. Our first job is to determine which variables we'll need to use: just one, which will be assigned the currently-running \FirstPart Synth. Also, if you didn't previously assign "TempoClock.default" to the variable "t_c", then it makes sense to do this now.
  5. The next thing our function must do is guarantee that we're going to have the right tempo. Use the "tempo_" Function with an argument in beats-per-second, to assign "TempoClock.default" a tempo of one beat per second.
  6. The next and last thing will be to schedule our sounds. First, we need to determine which events will need to be scheduled, and then at what times.
    1. Since \FirstPart is a SynthDef, we'll need to start it and stop it ourselves. Since it happens two times in the intended program, we'll need to do it twice.
    2. secondPart is a Function, and it stops itself when it's finished. We'll need to start it once and let it go.
    3. Just in case something takes a while to process, we'll start the first \FirstPart on beat one, rather than beat zero. We'll let it play for 60 seconds the first time, and 30 seconds the second time.
    4. In order to schedule the second appearance of \FirstPart, we need to know how long secondPart will take. Let's inspect the function and calculate how many beats it will take.
      • 1 beat of silence at the beginning,
      • 5 beats between the entrance of each SinOsc,
      • 10 SinOsc's,
      • 5 beats after the last SinOsc until the function stops.
      • This gives us 1 + ( 5 * 9 ) + 5 = 51. Why 5 * 9? Because although there are ten SinOsc's, there are only nine spaces between them; the last five-second space happens after the last SinOsc.
    5. This gives us the following schedule:
      • 1 beat: start \FirstPart
      • 61 beats: stop \FirstPart
      • 61 beats: start secondPart
      • 113 beats: start \FirstPart
      • 143 beats: stop \FirstPart
  7. Try to schedule the events for yourself, then test your program to make sure that it works as you intended. Here's what I wrote:
    t_c.sched( 1, { sound = \FirstPart ); } );
    t_c.sched( 61, {; } );
    t_c.sched( 61, { secondPart.value; nil; } );
    t_c.sched( 113, { sound = \FirstPart ); } );
    t_c.sched( 143, {; } );
    Why is the "nil" required after "secondPart"? Because that function returns a number. As you know, any scheduled function which returns a number will re-schedule itself to run that many beats after the previous execution began. Since "secondPart" returns the number of seconds it takes to finish, it will always be re-started as soon as it finishes. Including "nil" disallows this repetition.