top of page

Csound: Looping and Triggering Lines

  • kjcoleman7
  • Apr 1, 2018
  • 5 min read

The line opcode in Csound provides the functionality as the object of the same name in Max/MSP and PureData. Given three arguments, line will output a series of numbers interpolating between two values in a given amount of time.

The line object in Max has an outlet that triggers when the second value has been reached. This can be used to retrigger the object when the line object has finished and create a looping line. The opcode in Csound does not provide this functionality. Instead, if a line opcode is set to count from 0 to 1 in 1 second, it will continue to count up to 3 if left on for 3 seconds. It will keep running at the same rate indefinitely. We have to find another way of looping the line opcode.

Wrap

The wrap opcode is the easiest way to create a looping line. Wrap will take the output from another opcode (such as line) and wrap a signal that exceeds the higher limit back around to the lower limit.

The result of this code is shown in the fourth column below:

Problem solved. Sort of. Below is a practical example that makes use of the mincer opcode. (I will be using this opcode further in a future blog.)

Using wrap to loop audio.

We can use the looping sequence that wrap outputs as an index for an opcode that reads a function table containing a sound file. In this case, we'll use mincer so that we can play with the pitch function (though a simple loscil would do if you just want to play with looping a file).

I have a sample of an electric guitar and I want to read and play back the first 0.3 seconds of the sample over the course of 1 second. Reading the file slower than the original speed will have the effect of pitching the sample down. So, I set up a line object that takes a second to output between 0.01 and 0.3, and then use the wrap opcode so that I can let the sound play for 5 seconds without exceeding the bounds of the sample. The first argument of the mincer opcode is the time point in the sample that is being read. We use the output of the wrap opcode for this argument, providing a stream of time values for mincer.

So, now, if we let this run for 5 seconds, the mincer will play back from 0.01 seconds up to 0.3 seconds into the sound file, and then wrap back around to reading from 0.01 up to 0.3 seconds again, for the duration of the time. It sounds like this.

This is the whole code so far.

So, we can hear that every second, it wraps back around to the beginning. It works. A smoother sound can be achieved using a technique mentioned at the end of this blog.

Triggering Lines (An overly complex way to loop)

Using the wrap opcode allows us to loop audio for the duration of the instrument's life. What about triggering a line object during performance? This requires the use of global variables. A global variable is created before the instrument definitions in Csound, and contains the prefix 'g'. This time the time index provided to the mincer will not be the output of the wrap object, but the value of a global variable which is being fed by a line object.

Let's start by creating the global. I'll call it 'galine'.

Now the mincer opcode that will read the soundfile from a time index provided by the value of galine.

Now I'll create a line object that will feed the value of galine in a separate instrument (instr 2).

This line object activates whenever instr 2 is called and will keep counting up as long as instr 2 is active.

This time the wrap object is not being used. Instead the instrument containing the line is just being completely deactivated when the line has reached the end point that we have designated.

Now we need can call a new instance of instr 2 every time we want to restart the line. This can be done from the score or from an interactive interface.

That's it.

We can make a third instrument that calls an instance of instr 2 every time it finishes*, but there is no need. Just use wrap if you want to create a loop. Otherwise use a line in a new instrument if you want to trigger the line.

When I use this method, I leave the mincer running all the time. That way, when the line reaches its end point and is deactivated, the mincer continues to read the last value and creates a 'sample and hold' effect.

Let's do the same again with the third argument of the mincer. This is the pitch control.

(gkspeed in this image is an extra global that is the output of an interface item that I included.

The whole thing would look like this:

Now we can trigger the line, and manipulate the globals at will. We can create a little interface for it. There we have a simple little sound toy.

*If you're desperate to have that third instrument re-triggering the second instrument to create loop with the value of the global variable, it might look something like this:

Smoother Results and Experimentation

Using globals in order to trigger an instance of an instrument containing a line gives us the flexibility to trigger and turnoff a line at will. There is an added benefit of using this method. In the above example instr 2 contains a line that feeds the galine variable. If two instances of instr 2 are called then they will both be feeding galine with values. If the instantiation times of each instance of instr 2 are slightly offset from one another, the value of galine will vary around a point at the rate of the line's output. This can be used to create a chorus type of effect.

Calling two instances that are separated but close together can be achieved by creating an instrument that calls an instance of instrument 2 (instr 3). And then calling instrument 3 in the score at time 0. After one pass an instance of instrument 2 will be called. If an instance of instr 2 is also called in the score at time 0 them two versions of instr 2 will be called that are very close together.

The resulting sound is this:

https://soundcloud.com/colemank-1/line-triggering-with-overlap

I do not fully understand how this effect is being produced under the hood, but may look to harness it in future.

In my next Csound blog I will be looking further into using the mincer object in order to create a stuttering/splicing effect.


 
 
 

Kommentare


Recent Posts
bottom of page