All Projects → nettings → gpioctl

nettings / gpioctl

Licence: GPL-3.0 license
Control the ALSA mixer or generate JACK MIDI or OSC messages from rotary encoders and switches connected to GPIOs.

Programming Languages

c
50402 projects - #5 most used programming language
python
139335 projects - #7 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to gpioctl

go-bsbmp
Golang library to interact with Bosch Sensortec BMP180/BMP280/BME280/BMP388 temperature, pressure and humidity sensors via I2C-bus from Raspberry PI.
Stars: ✭ 41 (+127.78%)
Mutual labels:  gpio
endbasic
BASIC environment with a REPL, a web interface, a graphical console, and RPi support written in Rust
Stars: ✭ 220 (+1122.22%)
Mutual labels:  gpio
52-Weeks-of-Pi
Inspired by Shekhar Gulati's "52 technologies in 2016", I've decided to set a goal of 52 Pi ideas over the next year.
Stars: ✭ 54 (+200%)
Mutual labels:  gpio
Arduino-GPIO
General Purpose Input/Output (GPIO) library for Arduino
Stars: ✭ 43 (+138.89%)
Mutual labels:  gpio
funcd
Daemon for functional keys (works without X11)
Stars: ✭ 14 (-22.22%)
Mutual labels:  alsamixer
tinyfont
Text library for TinyGo displays
Stars: ✭ 37 (+105.56%)
Mutual labels:  gpio
moon c
문c 블로그 with ARM64 Linux Kernel 5.x
Stars: ✭ 17 (-5.56%)
Mutual labels:  gpio
w1-gpio-cl
Command line configured kernel mode 1-wire bus master driver. w1-gpio standard Linux module enhancement/substitution.
Stars: ✭ 17 (-5.56%)
Mutual labels:  gpio
gopio
Raspberry pi GPIO controller package(CGO)
Stars: ✭ 14 (-22.22%)
Mutual labels:  gpio
hcsr04
hcsr04 full function driver
Stars: ✭ 25 (+38.89%)
Mutual labels:  gpio
go-hx711
Golang HX711 interface using periph.io driver
Stars: ✭ 15 (-16.67%)
Mutual labels:  gpio
growbox
Code for my smart growbox experiment
Stars: ✭ 23 (+27.78%)
Mutual labels:  gpio
vdcd
vdcd - virtual device controller daemon/framework for digitalSTROM
Stars: ✭ 19 (+5.56%)
Mutual labels:  gpio
jean-pierre
A Raspberry Pi robot that helps people make their grocery list.
Stars: ✭ 41 (+127.78%)
Mutual labels:  gpio
gobot
Golang framework for robotics, drones, and the Internet of Things (IoT)
Stars: ✭ 7,869 (+43616.67%)
Mutual labels:  gpio
tinyspec-cling
tiny spectral synthesizer with livecoding support
Stars: ✭ 31 (+72.22%)
Mutual labels:  jack
5110LCD PCD8544.swift
A Swift library for the Nokia3310/5110 PCD8544 Monochrome LCD display
Stars: ✭ 28 (+55.56%)
Mutual labels:  gpio
hackenstein3D
Raycasting game for the Hack computer from Elements of Computing Systems / Coursera NAND2Tetris
Stars: ✭ 46 (+155.56%)
Mutual labels:  jack
hifiberry
This is a custom component to allow control of HifiberryOS devices in Home Assistant using the audiocontrol2 REST API.
Stars: ✭ 26 (+44.44%)
Mutual labels:  hifiberry
sapfy
Spotify daemon recorder and downloader
Stars: ✭ 55 (+205.56%)
Mutual labels:  jack

gpioctl

gpioctl has been written to provide hardware volume control for an audio engine running on the Raspberry Pi, via a rotary encoder connected to the GPIOs. It can directly interact with the ALSA mixer, or you can create JACK MIDI messages to remote-control any JACK MIDI capable client. Since it uses a generic GPIO interface via libgpiod, it might also be useful on other hardware platforms. I cannot test this personally, but your feedback is welcome.

gpioctl is written in C because it turned out that I couldn't get Python-based solutions to perform well enough to work with JACK at low latencies. If you don't need JACK, you might find Python friendlier to work with. A good example is this one: https://gist.github.com/savetheclocktower/9b5f67c20f6c04e65ed88f2e594d43c1

Usage

$ ./build/gpioctl -h

gpioctl v0.2.0 handles switches and rotary encoders connected to GPIOs, using the
portable libgpiod kernel interface, to send text messages to /dev/stdout.
If enabled at build time, you can also send JACK MIDI CC messages,
OSC messages, or directly interact with an ALSA mixer control.
We assume GPI pins have a pull-up, so the return should be connected to ground.

-h|--help      This help.
-V|--version   Print version and exit.
-v|--verbose   Print current controller values.

The following options may be specified multiple times. All parameters must be
separated by commas, no spaces. Parameters in brackets are optional.

-r|--rotary clk,dt,type,...
               Set up a rotary encoder.
               clk:     the GPI number of the first encoder contact (0-63)
               dt:      the GPI number of the second encoder contact (0-63)
               Depending on 'type', the remaining parameters are:

      ...,jack,cc,[ch[,min[,max[,step[,default]]]]]
               cc:      MIDI continous controller number (0-119)
               ch:      MIDI channel (1-16), default 1
               min:     minimum controller value (0-127), default 0
               max:     maximum controller value (0-127), default 127
               step:    the step size per 'click'(1-127), default 1
               default: the initial value, default is 'min'

      ...,alsa,control[,step]
               control: the name of a simple controller in ALSA mixer
               step: the step size in dB per click, default 3

       ...,osc,url,path[,min[,max[,step[,default]]]]
               url:     The OSC url of the receiver(s), such as
                        osc.udp://239.0.2.149:7000
               min:     minimum value (-2147483648 - 2147483647), default 0
               max:     maximum value (-2147483648 - 2147483647), default 100
               step:    the step size per click, default 1
               default: the initial value, default is 'min'

    ...,master,url[,step]
               Set up an network master controller for use with -R.
               url:     The OSC url of the receiver(s), such as
                        osc.udp://239.0.2.149:7000
               step:    the step size per click, default 3

    ...,stdout,format[,min[,max[,step[,default]]]]].
               format:  a string that can contain the special tokens '%gpi%'
                        (the pin number) and '%val%' (the value)
               min:     minimum value (-2147483648 - 2147483647), default 0
               max:     maximum value (-2147483648 - 2147483647), default 100
               step:    the step size per click, default 1
               default: the initial value, default is 'min'

-s|--switch sw,type...
               Set up a switch.
               sw:      the GPI pin number of the switch contact (0-63)
               Depending on 'type', the remaining parameters are:

      ...,jack,cc,[ch[,toggle[,min[,max[,default]]]]]
               cc:      MIDI continous controller number (0-120)
               ch:      MIDI channel (1-16), default 1
               toggle:  can be 0 (momentary on) or 1 (toggled on/off)
               min:     controller value when open (0-127), default 0
               max:     controller value when closed (0-127), default 127
               default: the initial value, default is 'min'

      ...,alsa,control
               control: the name of a simple controller in ALSA mixer
                        (switch will operate the MUTE function)

       ...,osc,url,path[,toggle[,min[,max[,default]]]]
               url:     An OSC url, such as osc.udp://239.0.2.149/gpioctl/level
               path:    An OSC path, such as /mixer/level
               toggle:  can be 0 (momentary on) or 1 (toggled on/off)
               min:     value when open (-2147483648 - 2147483647), default 0
               max:     value when closed (-2147483648 - 2147483647), default 100
               default: the initial value, default is 'min'

    ...,master,url
               Set up a network master controller for use with -S.
               url:     The OSC url of the receiver(s), such as
                        osc.udp://239.0.2.149:7000

    ...,stdout,format[,toggle[,min[,max[,default]]]]
               format:  a string that can contain the special tokens '%gpi%'
                        (the pin number) and '%val%' (the value)
               toggle:  can be 0 (momentary on) or 1 (toggled on/off)
               min:     minimum value (-2147483648 - 2147483647), default 0
               max:     maximum value (-2147483648 - 2147483647), default 1
               default: the start value, default is 'min'

-U|--osc-url   URL to listen to, e.g. osc.udp://239.0.2.149:7000
               This is mandatory if -R or -S are used.

-R|--rotary-slave control
               control: an ALSA mixer simple control

-S|--switch-slave control
               control: an ALSA mixer simple control (operates MUTE)

Pin numbers above are hardware GPIO numbers. They do not usually correspond
to physical pin numbers. For the RPi, check https://pinout.xyz/# and look
for the Broadcom ('BCM') numbers.
libgpiod does not know how to control the pull-up/pull-down resistors of your
GPIO pins. Use a hardware-specific external tool to enable them, or add
physical pull-ups.

gpioctl is meant to run as a daemon. Use CTRL-C or send a SIGTERM to exit.

Connecting rotary encoders

For testing, I'm using an ALPS incremental rotary encoder (model no. EC11E15244C0) with push-down switch. This one has three pins on one side for the rotary (clk, ret, dt), and two on the other for the switch (sw, ret).

A rotary works with two switches which open and close slightly out-of-phase. If you get an edge interrupt on [clk] and both switches are the same (either open or closed), you know you just went one click clockwise. If the switches are in opposite states, you went one click counter-clockwise.

Here's a Raspberry Pi 3B+ with a HifiBerry AMP2 the ALPS rotary encoder/switch connected to the GPIOs. I'm using GPIOs 17 (white), 27 (grey), 6 (purple) in this example, the ground is black. Check out the pins at https://pinout.xyz/#.

Figure 1

The wiring side: the rotary connections are visible on the left, with the return pin in the middle tied to the return of the switch and grounded. The solder blobs at the top and bottom don't do anything, they just secure the encoder case in place.

Figure 2

In case you were wondering: you can use as many encoders as you have GPIs (tested to up to four):

Figure 3

Enabling the pull-up resistors

libgpiod will set the pin direction to "input" automatically, but it is not currently able to set other pin features. So you will have to use a hardware-specific tool to enable pull-ups, or connect your controller board to an appropriate voltage source and add physical pull-ups.

Sadly, the wiringpi suite on the Raspberry Pi is no longer maintained. Thanks Gordon for your amazing work, and all the best!

The tool of choice is now raspi-gpio, check out tools/enable_input_and_pullups.sh for a practical example, and

$ raspi-gpio get

for a quick overview of the state of all GPIOs.

NOTE: if you are using any HATs in addition to gpioctl controllers, be sure the GPIO lines you are about to reconfigure are not in use. You might crash the system and even damage your hardware.

If your pin requirements do not change at runtime, you can also preconfigure your pin states via /boot/config.txt.

Controlling the ALSA mixer

In order to find the right mixer control, play some music and look at

$ amixer scontrols

Then try to manipulate a control with

$ amixer sset [YOURCONTROL] 30%

and see if the playback volume changes.

Once you've found the appropriate control name, plug it into the following command instead of "Digital", which is the default for HifiBerry AMP2 users. Now you can run

$ gpioctl -v -r 17,27,alsa,Digital -s 6,alsa,Digital

You can also run

$ watch -n 0.5 amixer sget [YOURCONTROL]

or

$ alsamixer

in another terminal and watch the mixer update live.

Sending JACK MIDI commands

Start a JACK server. Then open another terminal and run

$ jack_midi_dump

which will dump all incoming JACK MIDI messages to the screen.

In a third terminal, run

$ gpioctl -v -r 17,27,jack,1,15 -s 6,jack,1,16,1

If all goes well, you should see two new jack clients, which you connect:

$ jack_lsp
system:playback_1
system:playback_2
midi-monitor:input
gpioctl:midi_out
$ jack_connect gpioctl:midi_out midi-monitor:input

Now use the controls and watch the JACK MIDI events coming in. Of course the point is to use another JACK client that does useful things with those controller inputs. Ardour or mod-host are examples.

Sending OSC

There is now experimental support for sending OSC messages. To try it out, make sure your firewall is not blocking the respective port and IP. Here is a multicast example, it's extra fun if you run the following on several other hosts in the local network:

$ oscdump osc.udp://239.0.0.254:3000

Then, on the machine that has the rotary connected, try this:

$ gpioctl -r 17,27,osc,osc.udp://239.0.0.254:3000,/some/path/maybelevel,0,100,1,0 -s 6,osc,osc.udp://239.0.0.254:3000,/some/path/maybemute,1,0,1,0

This example will send the commands to a multicast IP, so that it can be received by multiple hosts. Of course you can also use normal IPs. The data type will always be 'i'.

Using OSC Master/Slave mode

If you have multiple nodes with soundcards that you wish to control as a group, you can use the Master/Slave mode via UDP multicast. On your "master", i.e. the one that has the rotary hardware, do

$ gpioctl -r 17,27,master:osc.udp://239.0.0.254:3000,4 -s 6,master/osc.udp://239.0.0.254:3000

and on the slave(s), do

$ gpioctl -U osc.udp://239.0.0.254:3000 -R Digital -S Digital

If your master machine also has a soundcard that should follow, it can be its own slave, like so:

$ gpioctl -U osc.udp://239.0.0.254:3000 -R Digital -S Digital -r 17,27,master,osc.udp://239.0.0.254:3000,4 -s 6,master,osc.udp://239.0.0.254:3000

If your slave has a card with multiple channels such as the AudioInjector Octo, you can link multiple channels to your slave instance:

$ gpioctl -U osc.udp://239.0.0.254:3000 -R DAC1 -R DAC2 -R DAC3 -R DAC4 

(The Octo does not have a mute switch in its mixer, so we only use faders here.)

Note that liblo does not reliably support IPv6 multicast, and that TCP support in gpioctl should be considered broken.

Using the stdout frontend

The most simple way of using gpioctl is to have it spit out controller values to standard output. The formatting option is currently not implemented and will be ignored. In its current state it makes little sense, and even less when you have -v or DEBUG mode active.

$ gpioctl -r 17,27,stdout,FOOBAR -s 6,stdout,FOOBAR,1

Building gpioctl

In addition to the usual system header files and libraries, gpioctl requires libgpiod-dev. If you want to use JACK MIDI, you need libjack-jackd2-dev or libjack-dev (untested). If you want to access the ALSA mixer, you need libasound2-dev. If you want to send OSC messages, you need liblo-dev and liblo-tools. I recommend installing wiringpi on the Pi or another hardware-specific GPIO controller tool for your platform. (Package names are for Raspbian, they may differ on your system.)

The build system is waf. My understanding of it is very limited. For now, from the root your working copy do

$ CFLAGS="-DDEBUG -g -Wall" ./waf configure  # for very verbose output, or
$ ./waf configure                            # for production code, or
$ ./waf configure --prefix=/foo              # if you don't like /usr/local/, and
$ ./waf                                      # to build

During the configuration step, you can selectively disable unneeded features with --disable-{alsa|jack|osc}.

You can run it without installing from ./build/gpioctl, or install it with

$ sudo ./waf install                         # installs to prefix set before, or
$ sudo ./waf install --destdir=/bar          # for packagers
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].