Working with Images

Getting the sprawl access point image

Download the operating system image for the sprawl access points! According to its postfix .xz the image is compressed with the XZ compression algorithm. Before writing the image to the sd card it has to be decompressed.

On Ubuntu/Debian you can install xz-utils and use unxz:

$ sudo apt-get install xz-utils
unxz sprawl_pi_image_20200628_shrinked.img.xz

On MacOS try the unarchiver. On Windows try the usual way to decompress files or download xz-utils.

Writing images on sd card

MacOS

➜  ~ diskutil list
/dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                 Apple_APFS Container disk1         1000.0 GB  disk0s2

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +1000.0 GB  disk1
                                 Physical Store disk0s2
   1:                APFS Volume OWC Aura Pro SSD - Data 520.8 GB   disk1s1
   2:                APFS Volume Preboot                 82.6 MB    disk1s2
   3:                APFS Volume Recovery                525.8 MB   disk1s3
   4:                APFS Volume VM                      2.1 GB     disk1s4
   5:                APFS Volume OWC Aura Pro SSD        11.2 GB    disk1s5

/dev/disk2 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *63.9 GB    disk2
   1:             Windows_FAT_32 boot                    268.4 MB   disk2s1
   2:                      Linux                         63.6 GB    disk2s2

disk2 seems to be the sd card with 64 GB. To access the raw device /dev/rdisk2 is used. To write to this device you have to be root (administrator). Unmount the device before using dd.

diskutil unmountDisk /dev/disk2
sudo dd if=rpi.img of=/dev/rdisk2 bs=4M

Linux

$ sudo dd if=rpi.img of=/dev/disk/by-id/
ata-PLDS_DVD-RW_DS8A8SH_S45N7592Z1ZKBE0758TK
ata-SAMSUNG_MZMPA016HMCD-000L1_S11BNEACC10413
ata-SAMSUNG_MZMPA016HMCD-000L1_S11BNEACC10413-part1
ata-SAMSUNG_MZMPA016HMCD-000L1_S11BNEACC10413-part2
ata-SAMSUNG_MZMPA016HMCD-000L1_S11BNEACC10413-part3
ata-SanDisk_SSD_PLUS_240GB_184302A00387
ata-SanDisk_SSD_PLUS_240GB_184302A00387-part1
ata-SanDisk_SSD_PLUS_240GB_184302A00387-part2
ata-SanDisk_SSD_PLUS_240GB_184302A00387-part3
ata-SanDisk_SSD_PLUS_240GB_184302A00387-part4
ata-SanDisk_SSD_PLUS_240GB_184302A00387-part5
mmc-SDC_0x000000e2
mmc-SDC_0x000000e2-part1
wwn-0x5001b448b9edd143
wwn-0x5001b448b9edd143-part1
wwn-0x5001b448b9edd143-part2
wwn-0x5001b448b9edd143-part3
wwn-0x5001b448b9edd143-part4
wwn-0x5001b448b9edd143-part5
$ sudo dd if=rpi.img of=/dev/disk/by-id/mmc-SDC_0x000000e2 bs=4M status=progress

Windows

On Windows the easiest way to write an image to a sd card is to use a dedicated application like Balena Etcher.

Envelopes: ADSR

Envelopes are an essential part of control in electronic music and computer music. They are used to shape the characteristics of sound or other processes over time and are an integral part of synthesizers. Since they are that basic and versatile, they will be introduced in this early section.


One of the most common envelopes, already featured in early synthesizers and in prominent examples as the MiniMoog, is the ADSR envelope (Hiyoshi, 1979). It is comprised of four segments:

  • Attack
  • Decay
  • Sustain
  • Release

Attack time, decay time and release time can usually be controlled by the user via dials or sliders, whereas the sustain time depends on the duration a key is pressed and the sustain level may depend on the stroke velocity. Depending on the settings, the ADSR model can generate amplitude and timbral envelopes for slowly evolving sounds like strings or sounds with sharp attacks and release:

Your browser does not support the HTML5 canvas tag

Attack Time:

Decay Time:

Sustain Level:

Sustain Time:

Release Time:


When used in synthesizers, this envelope can be used to control the overall level or the timbre - for example through the cutoff frequency of a filter or by means of partial amplitudes.


References

  • Teruo Hiyoshi, Akira Nakada, Tsutomu Suzuki, Eiichiro Aoki, and Eiichi Yamaga. Envelope generator. December 18 1979. US Patent 4,178,826.
    [BibTeX▼]
  • Working with Groups

    Creating Groups

    Groups - or group nodes - can be a very useful concept for keeping track of the signal flow. Without any further actions, all nodes are placed in the default Group 1. Additional groups can be arranged regarding the order of execution. A new group can be added from sclang as follows:

    ~g1 = Group.new();
    

    Relative Group Positions

    As with nodes, further groups can be added in relation to existing groups. The following action makes sure that a new group will be placed after the previously defined group:

    ~g2 = Group.after(~g1);
    

    Nested Groups

    Groups can contain other groups, allowing a hierarchical structure of nodes:

    ~g3 = Group.head(~g2);
    

    More on Groups

    The group object allows many more actions. They are listed in the SC documentation on groups. After adding another group before the third one

    ~g4 = Group.before(~g3);
    

    the server node structure looks as follows:

    /images/basics/sc-group-nodes.png

    The server does not know the groups by their variable names in sclang. Hence they are numerated. Node indices - or IDs - of groups can be assessed from the language:

    ~g1.nodeID;
    ~g2.nodeID;
    ~g3.nodeID;
    ~g4.nodeID;
    

    Exercise

    Exercise

    Use groups to sort the nodes from the example in the section on Combining Nodes

    FM Synthesis: Formula & Spectrum

    Pulse Width Modulation

    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 of other services, making it possible to launch a system in with many interrelations. They can be started and stopped during operation. Depending on the configuration, services can also be restarted automatically when crashing.


    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
    

    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 on every boot.

    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
    

    Using APIs with Python

    Python & APIs

    With the modules requests and json it is easy to get data from APIs with Python. Using the above introduced methods for sequencing, the following example requests a response from https://www.boredapi.com/:

    #!/usr/bin/env python3
    
    import requests
    import json
    
    response = requests.get("https://www.boredapi.com/api/activity")
    data     = response.json()
    
    print(json.dumps(data, sort_keys=True, indent=4))
    
    # print(data["activity"])
    

    Combining Nodes in SuperCollider

    Creating and Connecting Nodes

    Audio buses can be used to connect synth nodes. In this example we will create two nodes - one for generating a sound and one for processing it. First thing is an audio bus:

    ~aBus = Bus.audio(s,1);
    

    The ~osc node generates a sawtooth signal and the output is routed to the audio bus:

    ~osc = {arg out=1; Out.ar(out,Saw.ar())}.play;
    
    ~osc.set(\out,~aBus.index);
    

    The second node is a simple filter. Its input is set to the index of the audio bus:

    ~lpf = {arg in=0; Out.ar(0, LPF.ar(In.ar(in),100))}.play;
    
    ~lpf.set(\in,~aBus.index);
    

    Warning

    Although everything is connected, there is no sound at this point. SuperCollider can only process such chains if the nodes are arranged in the right order. The filter node can be moved after the oscillator node:


    Moving Nodes

    /images/basics/sc-order-1.png

    Node Tree before moving the processor node.


    The moveAfter() function is a quick way for moving a node directly after a node specified as the argument. The target node can be either referred to by its node index or by the related name in sclang:

    ~lpf.moveAfter(~osc)
    

    /images/basics/sc-order-2.png

    Node Tree after moving the processor node.

    Pure Data: Send-Receive & Throw-Catch

    Send & Receive

    Control Rate

    Send and receive objects allow a wireless connection of both control and audio signals. The objects are created with send and receive or short s and r for control rate signals and get one argument - a string labeling the connection.

    Local Sends

    Prepending a $0- to a send label turns it into a local connection. These are only valid inside a patch and its subpatches but not across different abstractions. The example send-receive-help.pd shows the difference between local and global sends when used in both cases. It relies on the additional abstraction send-receive.pd which needs to be in the same directory:

    /images/basics/pd-send-receive.png

    Send and receive of control signals with subpatch and abstraction.


    The inside of both the subpatch and the abstraction are identical:

    /images/basics/pd-send-receive-sub.png

    Inside of send-receive and the subpatch.


    Audio Rate

    Audio send and receives follow the same rules as control ones. They are created with an additional ~, as usual for audio objects. The example send-receive-audio.pd shows the use of these buses:

    /images/basics/pd-send-receive.png

    Send and receive of audio signals with subpatch and abstraction.


    Throw & Catch

    Throw and catch are bus extensions of the above introduced send-receive method, only for audio signals. Unlike with s~ and r~, it is possible to send multiple signals to one catch~. This allows a flexible audio routing and grouping without a lot of lines. The example throw-catch.pd throws four sine waves to a common bus for a minimal additive synthesis:

    /images/basics/pd-throw-catch.png

    Using throw and catch to merge four signals.

    Sampling & Aliasing: Square Example

    For the following example, a sawtooth with 20 partials is used without band limitation. Since the builtin Web Audio oscillator is band-limited, a simple additive synth is used in this case. At a pitch of about \(2000 Hz\), the aliases become audible. For certain fundamental frequencies, all aliases will be located at actual multiples of the fundamental, resulting in a correct synthesis despite aliasing. In most cases, the mirrored partials are inharmonic and distort the signal and for higher fundamental frequencies the pitch is fully dissolved.

    Pitch (Hz):

    Output Gain:

    Time Domain:

    Frequency Domain:


    Anti-Aliasing Filters

    In analog-to-digital conversion, simple anti-aliasing filters can be used to band-limit the input and discard signal components above the Nyquist frequency. In case of digital synthesis, however, this principle can not be applied. When generating a square wave signal with an infinite number of harmonics, aliasing happens instantaneously and can not be removed, afterwards.

    Band Limited Generators

    In order to avoid the aliasing, band-limited signal generators are provided in most audio programming languages and environments.



    Contents © Henrik von Coler 2021 - Contact