I just finished a mono looper in Pure Data and I want to share it. It has a few simple functions but it can be used as a base for more complex projects.
History. I've been using SooperLooper for a while and it works OK. However, some functions are not working properly so I decided to create my own looper in Pure Data. The final goal is to create a looping system able to route different sources to any loop and be able to include some effects using a plugin host. But that's for later.
Overview. I divided this project in 2 patches: a Main patch just to send/receive the audio/control signals and the MonoLooper patch which is the loop machine. I'm using 48HKz sampling rate and there is a table to store up to 10 seconds of sound in RAM (you can easily modify the table size to change the max loop length).
This patch gets the audio input from the sound card, sends it to the MonoLooper and then sends the loop audio output back to the sound card. It also sends all the control signals to the MonoLooper:
This patch has mainly 4 elements: Inputs, Recorder, Player and Looper. Below I will explain how they work.
It just gets all inputs from the Main patch. There is one audio [inlet] and 8 control [inlet]s.
This element receives [StartRecording] (*1) and [StopRecording] (*2) signals from the Main patch.
The [StartRecording] does basically 4 things:
I'm using a trigger with 4 bangs (*6) to execute the tasks mentioned previously in the right order.
The [StopRecording] does 3 things:
After you record some audio, the [LoopLength] (*9) is sent to the PLAYER section.
This section plays the loop using the [tabplay~] object (*1). The maximum loop length is 10 seconds, but when a loop is being played, the [LoopLenght] (*2) is sent to [tabwrite~] as part of the play message (*3). The sound is sent to the [outlet~] (*4) and also [PlayLoop] signal (*5) is sent to the LOOPER section. This is basically a bang sent each time that the [tabplay~] finishes to play the current loop. Also there is a [Direct] (*6) option. When active it allows you to hear what is bein recorded by multiplying the audio signal input by 1 (otherwise is multiplied by 0). If [StoPlayLoop] signal is sent, a [stop( message is sent to the [tabplay~] (*7).
This section is the trickyest one. It controls most of the looping functions.
[AutoStartLoop] defines if the loop will start playing after [RecordStop] is executed. It is done by a [spigot] that allows/denyes the [RecordStop] signal to start playing the loop and a [toggle] that store the logic condition.
[PlayLoop] allows to play the loop forever. This signal it is sent by the Main patch but also by the [tabplay~] when it finishes the current reproduction of the loop.
[PlayOnce] plays the loop and then deactivate [PlayLoop] by a [toggle] and a [spigot]. The [toggle] state changes when the loop finishes, so it's possible to play the loop (or play once) again.
[StopPlayLoopSync] deactivates the [PlayLoop] by a [toggle] and a [spigot]. In this case the play action is not interrupted but the [PlayLoop] signal is interrupted. The [PlayLoop] signal is used to reset the [toggle] state, so it's possible to play the loop (or play once) again.
There is an [initbang] which sets the [toggle] to 1 when the patch is loaded.
NOTE1: If you look the MonoLoop closely you will find that all variable names and the table have a $0 at the end. This is extremely useful because it allows you to create different instances of the MonoLooper by using a different index number on each instance. If you check the Main patch you will see that [MonoLoop 1] is being used. Then, if you want to use another MonoLoop you have to change the index to a different number. If you don't use $0 (which is the same that use MonoLooper with the same index) you will find that variables from different instances have the same name, therefore the loops won't work. I spent a couple of hour trying to solve that problem when I was trying to create 2 MonoLooper instances for a stereo looper.
NOTE2: Yo can use $0, $1 and so one if you need different indexes in a patch. Then, you can use them for creating (conceptually) multidimensional arrays. In my case I just have one dimension array because I just need to create many instances of the same object. More complex patches may need multi dimensional structure.
My idea is to polish this module a little bit, create other functions (time stretch, pitch, etc) and then use it as a component of a big loop system. There is lot of work to do but I think this is a good start.
The full patch can be downloaded here