Max for Live: Light Dependent Resistor

This example shows how to send serial data from a single sensor from an Arduino to Max for Live. The stream of data will be used to control the cutoff frequency of a subtractive synth patch.


Breadboard Circuit

The breadboard circuit for this example is the same used in the first Arduino-Sensor-Circuit:

/images/basics/ldr_input_fritzing.png

Arduino Code

The same Arduino code can be used to send data to Max or Max for Live:

int analogInput = 0;

void setup()
{
  Serial.begin(9600);
}

void loop()
{

  float value = analogRead(analogInput);

  Serial.println(value);

  delay(5);
}

Max 4 Live Patch

The following patch is a Max Instrument` which has two audio outputs. It can be used like any other Live synthesizer.

No additional objects or packages are required for getting the Arduino's data to Max or Max for Live via USB serial. Receiving the data sent from the above Arduino code is managed with the serial object in Max. It needs the same baud rate as the sender (9600) as second argument and the Arduino's serial port ID as first argument. Clicking print gives the list of serial devices in the max console. Enter the result into the serial object (in this case 'd' for 'usbmodem').

Once the proper id is set, the metro object can be started using the toggle switch. Every ten milliseconds, data is read from the serial port. The following objects unpack and format the stream and turn it into an integer. The resulting values are just scaled and used for the cutoff frequency of two parallel low pass filters.

/images/basics/arduino/max4live_ldr.png

LDR controlled subtractive synth in the Max device editor.


Additional Resources

This example works with the same approach.

Faust for Web Audio

External Resources

Read the slides by Myles Borins for an introduction about Faust with Web Audio.

The minimal examples by Yosuke Torii are a good way to get started.

Self-Contained HTML

Using the faust2webaudiowasm it is pretty easy to create self-contained HTML instruments. They can run within any webserver.

White Tone Example

The Sine Example

If we want to use Faust-built DSP elements in a more flexible way, there is another way which delivers

$ faust2wasm sine.dsp

Karplus-Strong Example

Chowning & Music IV

With FM synthesis (see CMB: A Brief History ), John Chowning invented a wide spread synthesis technique, which was used extensively in 1980s pop music. When exploring this novel technique, he also lay the foundation for computer-based audio spatialization. With Music 10, a descendant of Max Mathews MUSIC IV, Chowning was able to create four-channel compositions with programmed movements of virtual sound sources. This object-based approach is still used in most cases today.

Algorithm

In Turenas (1972), source movements are enhanced with Doppler shift and the proper handling of the direct-to-reverb ratio:

/images/spatial/turenas_movement.png

Displaced circular movement with Doppler shift and reverberation (Chowning, 2011).


The above presented technique was used with Lissajous movements, which are characteristic for Turenas:

/images/spatial/turenas_lissajous.png

Stereo Version


References

2018

  • Christoph von Blumröder. Zur bedeutung der elektronik in karlheinz stockhausens œuvre / the significance of electronics in karlheinz stockhausen's work. Archiv für Musikwissenschaft, 75(3):166–178, 2018.
    [abstract▼] [details] [BibTeX▼]

2015

  • Martha Brech and Henrik von Coler. Aspects of space in Luigi Nono's Prometeo and the use of the Halaphon. In Martha Brech and Ralph Paland, editors, Compositions for Audible Space, Music and Sound Culture, pages 193–204. transctript, 2015.
    [details] [BibTeX▼]
  • Michael Gurevich. Interacting with Cage: realising classic electronic works with contemporary technologies. Organised Sound, 20:290–299, 12 2015. doi:10.1017/S1355771815000217.
    [details] [BibTeX▼]

2011

  • John Chowning. Turenas: the realization of a dream. In Proceedings of the 17th Journées d\rq Informatique Musicale. 2011.
    [details] [BibTeX▼]

2010

2008

  • Marco Böhlandt. “kontakte” – reflexionen naturwissenschaftlich-technischer innovationsprozesse in der frühen elektronischen musik karlheinz stockhausens (1952–1960). Berichte zur Wissenschaftsgeschichte, 31(3):226–248, 2008.
    [details] [BibTeX▼]
  • Jonas Braasch, Nils Peters, and Daniel Valente. A loudspeaker-based projection technique for spatial music applications using virtual microphone control. Computer Music Journal, 32:55–71, 09 2008.
    [details] [BibTeX▼]

Spatial Granular Synthesis

Granular synthesis - introduced in detail in the Sound Synthesis Introduction - is particularly well suited for extensions in the spatial domain. Each grain can be assigned an individual position, thus creating spatially extended textures. Granularity also increases the localization of the single events, this emphasizing the spread. Hence, various approaches have been proposed in the past and present, implemented in all common audio programming environments.


Various Approaches

Curtis Roads' book Microsound features several examples of spatial granular synthesis (Roads, 2004). Scattering - a stochastic panning of single grains - is introduced by McLeran et al. (McLeran, 2008). The approach is designed to work with stereo and 2D loudspeaker setups. The BMSwarmGranulator (Wilson, 2008) uses the Boids algorithm for spatial granular sound textures. Designed for the BEAST, the approach aims at a 'diffuse but localized sound', rather then individually perceivable grains.


Crowd Noise Synthesis

A project at TU Berlin aimed at the parametric synthesis of crown noise, more precisely the indistinct chatter (babbling) of large groups of people (Grimaldi, 2017). The project is best described on the corresponding paper or the master thesis.


References

2017

  • Grimaldi, Vincent and Böhm, Christoph and Weinzierl, Stefan and von Coler, Henrik. Parametric Synthesis of Crowd Noises in Virtual Acoustic Environments. In Proceedings of the 142nd Audio Engineering Society Convention. Audio Engineering Society, 2017.
    [details] [BibTeX▼]

2015

  • Stuart James. Spectromorphology and spatiomorphology of sound shapes: audio-rate AEP and DBAP panning of spectra. In Proceedings of the International Computer Music Conference (ICMC). 2015.
    [details] [BibTeX▼]
  • Ryan McGee. Spatial modulation synthesis. In Proceedings of the International Computer Music Conference (ICMC). 2015.
    [details] [BibTeX▼]

2009

  • Alexander Müller and Rudolf Rabenstein. Physical modeling for spatial sound synthesis. In Proceedings of the International Conference of Digital Audio Effects (DAFx). 2009.
    [details] [BibTeX▼]

2008

  • Scott Wilson. Spatial swarm granulation. In Proceedings of the International Computer Music Conference (ICMC). 2008.
    [details] [BibTeX▼]
  • David Kim-Boyle. Spectral spatialization - an overview. In Proceedings of the International Computer Music Conference (ICMC). Belfast, UK, 2008.
    [details] [BibTeX▼]

2004

  • Curtis Roads. Microsound. The MIT Press, 2004. ISBN 0262681544.
    [details] [BibTeX▼]

2002

  • David Topper, Matthew Burtner, and Stefania Serafin. Spatio-operational spectral (SOS) synthesis. In Proceedings of the International Conference of Digital Audio Effects (DAFx). Singapore, 2002.
    [details] [BibTeX▼]

Using YAML for Configuration

At some point, a program might require more arguments on startup than a command line call can manage without complications. In that case it can help to work with configuration files, which are passed to the binary when starting it. This can be done in many ways, including plain text files or markup languages like XML, Markdown, JSON or others.

The examples in this module use YAML for passing configuration data. YAML is human-readable and easy to edit, which allows quick changes to configurations.


The YamlMan Class

The YAML manager class YamlMan is used in all following examples which make use of YAML for parsing configuration parameters in adapted versions.

The Constructor

The constructor of the class is passed a file path to a YAML file as argument:

YamlMan::YamlMan(std::string filepath)

The following behavior is specific for each example, storing the values from the YAML file to member variables:

YAML::Node config = YAML::LoadFile(filepath);

// access YAML nodes:
param1 = config["param1"].as<std::string>();
param2 = config["param2"].as<int>();
param3 = config["param3"].as<double>();

Envelopes in PD

Temporal envelopes are an essential building block of sound synthesis algorithms. They are introduced in the Control Section of the CMB content:

ADSR in PD

The ADSR envelope is the most widely used temporal envelope. The PD help files contain an example, which can serve as a starting point for an ADSR object. It can also be downloaded here: ADSR


Once stored, the object can be used in custom patches to control arbitrary parameters. The following example controls the gain of a sine wave oscillator with an ADSR envelope. The adsr object has six inlets:

  • 1: the trigger

  • 2: the peak value

  • 3: the attack time (ms)

  • 4: the decay time (ms)

  • 5: the sustain amount (0...100%)

  • 6: the release time (ms)

The delay object emulates a 555 ms key press. The only outlet is an audio rate signal with the envelope:

/images/basics/pd-adsr.png

Pulse Width Modulation

Pulse Width Modulation (PWM) is a method for changing the timbre of a square wave. It is frequently found in analog and digital synthesizers as a means for enriching a sound, for example in pads.

A PWM signal can be generated with a case based logic, respectively a threshold. In programming, this can be implemented with a phasor and the pulse width $\tau$:

$$ \mathrm{PWM}(t) = \begin{cases} 1 \ \ \ \ \text{for} \ t<= \frac{T \tau}{100} , \\ -1 \ \text{for} \ t> \frac{T \tau}{100} , \end{cases} $$

The pulse width usually takes values beween $0\%$ and $100\%$:

Organizing Processes with systemd

systemd is a set of tools managing, among other things, the startup procedure on Linux systems. Within the Linux user and developer community, there is a debate whether systemd violates the Unix philosophy - however, it works well for starting all the software components we need when booting the server or the Access Points.

System services can be started in dependence on other services, This makes it possible to start a system with many interrelations. They can be started and stopped during operation. Depending on the configuration, the services can also be restarted automatically if they crash.


Creating Services

systemd services can be declared as user services or system services. They are defined in text files, which need to be located in one of the the following directories:

/usr/lib/systemd/user
/usr/lib/systemd/system

The JACK Service

The JACK service needs to be started before all other audio applications, since they rely on a running JACK server. A file jack.service defines the complete service:

[Unit]
Description=Jack audio server
After=sound.target local-fs.target

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
PrivateTmp=true
Environment="JACK_NO_AUDIO_RESERVATION=1"
ExecStart=/usr/bin/jackd -P 90 -a a -d dummy -p 128
LimitRTPRIO=95
LimitRTTIME=infinity
LimitMEMLOCK=infinity
User=studio

JACK must be run as a normal user. The file above describes a system service that starts jack as user studio. But only administrators are allowed to control system services. If we want to control a service as a normal user we need a user service without the User=studio entry.

Managing Services

Once the service files are in place, several simple commands are available for controlling them. They differ, depending on whether a user service or system service is controlled. The following examples refer to the JACK user service. Controlling system services requires root privileges and do not need the --user flag.

Starting a Service

systemctl --user start jack.service

Stopping a Service

systemctl --user stop jack.service

Activating a Service

Activating a service creates a symlink in ~/.config/systemd/user/multi-user.target.wants/jack.service, pointing to the original file /usr/lib/systemd/user/jack.service. Afterwards, the system is launched after the first login of the user and stopped after the last user session exits.

systemctl --user enable jack.service

Deactivating a Service

systemctl --user disable jack.service

Getting a Service's Status

The following command prints a system's status:

systemctl --user status jack.service

When the JACK sevice has been started sucessfully, the output looks as follows:

 ● jack.service - Jack audio server
  Loaded: loaded (/usr/lib/systemd/user/jack.service; enabled; vendor preset: enabled)
  Active: active (running) since Tue 2021-04-13 23:00:14 BST; 3s ago
Main PID: 214518 (jackd)
  CGroup: /user.slice/user-1000.slice/user@1000.service/jack.service
          └─214518 /usr/bin/jackd -P 90 -a a -d dummy -p 256

Start user service on boot

Sometimes it is practical to have a user session running after the last session closes. For example if you access a server only via SSH. To achieve this we have to set the specific user to be lingering. This user's services will start at boot and quit at shutdown now.

# loginctl enable-linger studio

Organizing Processes with systemd

systemd is a set of tools managing, among other things, the startup procedure on Linux systems. Within the Linux user and developer community, there is a debate whether systemd violates the Unix philosophy - however, it works well for starting all the software components we need when booting audio servers.

System services can be started in dependence on other services, This makes it possible to start a system with many interrelations. They can be started and stopped during operation. Depending on the configuration, the services can also be restarted automatically if they crash.


Creating Services

systemd services can be declared as user services or system services. They are defined in text files, which need to be located in one of the the following directories:

/usr/lib/systemd/user
/usr/lib/systemd/system

The JACK Service

The JACK service needs to be started before all other audio applications, since they rely on a running JACK server. A file jack.service defines the complete service:

[Unit]
Description=Jack audio server
After=sound.target local-fs.target

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
PrivateTmp=true
Environment="JACK_NO_AUDIO_RESERVATION=1"
ExecStart=/usr/bin/jackd -P 90 -a a -d dummy -p 128
LimitRTPRIO=95
LimitRTTIME=infinity
LimitMEMLOCK=infinity
User=studio

JACK must be run as a normal user. The file above describes a system service that starts jack as user studio. But only administrators are allowed to control system services. If we want to control a service as a normal user we need a user service without the User=studio entry.

Managing Services

Once the service files are in place, several simple commands are available for controlling them. They differ, depending on whether a user service or system service is controlled. The following examples refer to the JACK user service. Controlling system services requires root privileges and do not need the --user flag.

Starting a Service

systemctl --user start jack.service

Stopping a Service

systemctl --user stop jack.service

Activating a Service

Activating a service creates a symlink in ~/.config/systemd/user/multi-user.target.wants/jack.service, pointing to the original file /usr/lib/systemd/user/jack.service. Afterwards, the system is launched after the first login of the user and stopped after the last user session exits.

systemctl --user enable jack.service

Deactivating a Service

systemctl --user disable jack.service

Getting a Service's Status

The following command prints a system's status:

systemctl --user status jack.service

When the JACK sevice has been started sucessfully, the output looks as follows:

 ● jack.service - Jack audio server
  Loaded: loaded (/usr/lib/systemd/user/jack.service; enabled; vendor preset: enabled)
  Active: active (running) since Tue 2021-04-13 23:00:14 BST; 3s ago
Main PID: 214518 (jackd)
  CGroup: /user.slice/user-1000.slice/user@1000.service/jack.service
          └─214518 /usr/bin/jackd -P 90 -a a -d dummy -p 256

Start user service on boot

Sometimes it is practical to have a user session running after the last session closes. For example if you access a server only via SSH. To achieve this we have to set the specific user to be lingering. This user's services will start at boot and quit at shutdown now.

# loginctl enable-linger studio