{"id":17258137,"url":"https://github.com/ffont/shepherd","last_synced_at":"2025-04-14T06:11:25.932Z","repository":{"id":37457685,"uuid":"365215534","full_name":"ffont/shepherd","owner":"ffont","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-23T10:35:26.000Z","size":26201,"stargazers_count":15,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T19:54:31.619Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ffont.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-07T11:45:01.000Z","updated_at":"2025-01-19T01:21:54.000Z","dependencies_parsed_at":"2023-02-12T22:16:55.020Z","dependency_job_id":null,"html_url":"https://github.com/ffont/shepherd","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffont%2Fshepherd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffont%2Fshepherd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffont%2Fshepherd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffont%2Fshepherd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ffont","download_url":"https://codeload.github.com/ffont/shepherd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248830395,"owners_count":21168272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T07:19:38.014Z","updated_at":"2025-04-14T06:11:25.903Z","avatar_url":"https://github.com/ffont.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shepherd\n\nShepherd is an **open source MIDI sequencer** which I built to learn how sequencers work and to have an open, hackeable\nenvironment to experiment with music sequencing. Shepherd consists of a *backend* application written in C++ using JUCE \nwhich does the actual sequencing of the MIDI messages (see [Shepherd](/tree/main/Shepherd) folder in this repo), and a *controller* application (written in Python) which controls\nthe backend and provides a user interface. Bi-directional communication between the backend and the controller is \nachieved using Web Sockets. Even though in this repository we provide code to make it very easy to develop alternative\ncontroller applications using Python (see below), these could be developed in any other language as long as they \nsupport Web Sockets for communication with the backend and implement the communication protocol to send/receive \nmessages to/from the backend.\n\nOne of my main goals when starting to develop Shepherd was that it should be able to run on a **Raspberry Pi** (Rpi) and \nshould be controllable from a hardware device that should serve as its user interface. In particular, I focused on using\n**Ableton's Push2** as the user interface for Shepherd. In the past I developed a Python package to control Ableton's \nPush2, [push2-python](https://github.com/ffont/push2-python), therefore I developed a Python-based controller for \nShepherd that uses Push2 as the user interface. That *controller script* is provided in this repository in the \n[Push2Controller](/tree/main/Push2Controller) folder. To communicate with the backend, I implemented a Python\npackage, [pyshepherd](/tree/main/pyshepherd), which is used by Push2Controller, but that could be easily reuse by \nother controller scripts interfacing with the backend.\n\nShepherd is work in progress and will most likely be never finished. It is released under the **GPLv3** open source \nsoftware license (see below) and I can't really provide support for it, but if anyone is trying to reuse it I'll be\nhappy to help.\n\n\n## Shepherd Backend\n\nThe Shepherd backend implements a MIDI clip trigger system which works in an Ableton Live-like style. Shepherd *sessions* consist of a number of MIDI tracks and a number of scenes that must be defined when creating a new session (and can't be changed until a new session is loaded). This creates a *num tracks* * *num scenes* grid of MIDI clips that can be triggered independently, but only one clip per track can be played at the same time.\n\nTODO: add more general information about the backend, block diagram, description of features\n\n\n### Building the backend\n\nThe first step, common to all platforms, clone repository (with submodules):\n\n```\ngit clone https://github.com/ffont/shepherd.git \u0026\u0026 cd shepherd \u0026\u0026 git submodule update --init\n```\n\n#### macOS\n\nBefore compiling, you'll need to install `openssl` (e.g. `brew install openssl`), as it is required for the backend.\n\nThen you can compile the Shepherd backend from XCode (opening the XCode project in `Shepherd/Builds/MacOSX`), or from \nthe terminal using `xcodebuild` command:\n\n```\ncd Shepherd/Builds/MacOSX\nxcodebuild -arch 'x86_64' -configuration Release GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS LLVM_LTO=NO'\n```\n\nNote that I'm not running an arm-based mac and I had to force-set the architecture in the build command \n(`-arch 'x86_64'`) to make it compile properly, not sure why...\n\nIf compiled from XCode, Shepherd will start running right after compilation, otherwise you can run it like:\n\n```\ncd Shepherd/Builds/MacOSX/build/Release/Shepherd.app/Contents/MacOS\n./Shepherd\n```\n\nNOTE: If compiling in Debug mode (this is what XCode will do by default if you compile it from there), Shepherd backend\nwill open a window when running which will load the Push2 simulator implemented in Push2Controller (if available), but\nthis will not happen when running in Release mode.\n\n\n#### Linux (including RaspberryPi running Raspbian)\n\nBefore compilation, you'll need to install [JUCE linux dependencies]( https://github.com/juce-framework/JUCE/blob/master/docs/Linux%20Dependencies.md\n), and also `xvfb`, which is used to run Shepherd headlessly without any errors:\n\n```\nsudo apt update\nsudo apt install libasound2-dev libjack-jackd2-dev \\\n    libcurl4-openssl-dev  \\\n    libfreetype6-dev \\\n    libx11-dev libxcomposite-dev libxcursor-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev \\\n    libwebkit2gtk-4.0-dev \\\n    libglu1-mesa-dev mesa-common-dev\nsudo apt-get install xvfb\n```\n\nThen, you can compile using `make`:\n\n```\ncd /home/pi/shepherd/Shepherd/Builds/LinuxMakefile\nmake CONFIG=Release -j4\n```\n\nOnce compiled, you can run Shepherd backend like:\n\n```\ncd /home/pi/shepherd/Shepherd/Builds/LinuxMakefil/build/\n./Shepherd\n```\n\n\n### Backend configuration files\n\nShepherd uses configuration files to set some general settings and, most importantly, to define a list of input/output\nMIDI devices that will be accessible from the backend when running. In the context of Shepherd, these MIDI devices are\ncalled *hardware devices* although this can include any type of devices that offers input/output MIDI ports, being it\na real hardware device or some software creating virtual MIDI ports. A `backendSettings.json` file and a \n`hardwareDevices.json` file should be placed in a 'Shepherd' folder in the user Documents folder \n(i.e. `~/Documents/Shepherd/`). Below are template to create these files.\n\n#### backendSettings.json\n\nThis file is used to specify the MIDI devices that will be used to send metronome MIDI messages, to send MIDI clock\nmessages, and a special kind of MIDI clock syncing required to send tempo information to Ableton's push. This file\nis **optional**, and if left blank then no metronome note messages and no MIDI clock data will be sent to any device.\nThis is how the `backendSettings.json` should look like:\n\n```json\n{\n    \"metronomeMidiDevice\": \"OUTPUT_MIDI_DEVICE_NAME\",\n    \"metronomeMidiChannel\": \"MIDI_DEVICE_CHANNEL_FROM_1_TO_16\",\n    \"midiDevicesToSendClockTo\": [\"OUTPUT_MIDI_DEVICE_NAME1\", \"OUTPUT_MIDI_DEVICE_NAME2\", ...],\n    \"pushClockDeviceName\": \"OUTPUT_MIDI_DEVICE_NAME\",\n}\n```\n\nFor example, in my Rpi-based setup, my `backendSettings.json` file looks like this: \n\n```json\n{\n    \"metronomeMidiDevice\": \"ESI M4U eX MIDI 5\",\n    \"metronomeMidiChannel\": \"16\",\n    \"midiDevicesToSendClockTo\": [],\n    \"pushClockDeviceName\": \"Ableton Push 2 MIDI 1\",\n}\n```\n\n#### hardwareDevices.json\n\nThis file **is mandatory** if you want Shepherd to be able to communicate with MIDI devices of any kind (which you\nsurely do as otherwise Shepherd is useless :)). Using this file you configure a number of input and  output \n*hardware devices* to which you give a name, indicate the corresponding MIDI port names and add some other extra info. \nThis is how the `hardwareDevices.json` should look like:\n\n```json\n[\n\t{\n            \"type\": \"output\",\n            \"name\": \"A GIVEN NAME\",\n\t    \"shortName\": \"A GIVEN NAME WHICH IS SHORTER\",\n\t    \"midiChannel\": \"MIDI_DEVICE_CHANNEL_TO_SEND_MESSAGES_TO_FROM_1_TO_16\",\n\t    \"midiOutputDeviceName\": \"OUTPUT_MIDI_DEVICE_NAME:\"\n\t},{\n            \"type\": \"input\",\n            \"name\": \"A GIVEN NAME\",\n\t    \"shortName\": \"A GIVEN NAME WHICH IS SHORTER\",\n\t    \"midiInputDeviceName\": \"INPUT_MIDI_DEVICE_NAME\"\n\t},\n\t...\n]\n```\n\nIt can contain any number of input/output hardware devices. Here is an example `hardwareDevices.json` that I use in\nmy local development setup:\n\n```json\n[\n\t{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 1\",\n\t    \"shortName\": \"B1-1\",\n\t    \"midiChannel\": 1,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 2\",\n\t    \"shortName\": \"B1-2\",\n\t    \"midiChannel\": 2,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 3\",\n\t    \"shortName\": \"B1-3\",\n\t    \"midiChannel\": 3,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 4\",\n\t    \"shortName\": \"B1-4\",\n\t    \"midiChannel\": 4,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 5\",\n\t    \"shortName\": \"B1-5\",\n\t    \"midiChannel\": 5,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 6\",\n\t    \"shortName\": \"B1-6\",\n\t    \"midiChannel\": 6,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 7\",\n\t    \"shortName\": \"B1-7\",\n\t    \"midiChannel\": 7,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"output\",\n            \"name\": \"Bus1 ch 8\",\n\t    \"shortName\": \"B1-8\",\n\t    \"midiChannel\": 8,\n\t    \"midiOutputDeviceName\": \"IAC Driver Bus 1\"\n\t},{\n            \"type\": \"input\",\n            \"name\": \"Push\",\n\t    \"shortName\": \"Push\",\n\t    \"midiInputDeviceName\": \"Push2Simulator\",\n\t    \"controlChangeMessagesAreRelative\": true,\n\t    \"notesMapping\": \"-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\",\n\t    \"controlChangeMapping\": \"-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,64,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\"\n\t},{\n            \"type\": \"input\",\n            \"name\": \"iConKeyboard\",\n\t    \"shortName\": \"iConKeyboard\",\n\t    \"midiInputDeviceName\": \"iCON iKEY V1.02\"\n\t}\n]\n```\n\n\n## Shepherd Controllers\n\n### Push2Controller\n\nThe Push2Controller is a Python 3 script which interacts with the Shepherd backend and a Push2 device to provide the UI.\nTo run Shepherd Controller you'll need to install the Python requirements and simply run the app:\n\n```\npip install -r requirements.txt\npython app.py\n```\nThe Shepherd Controller app is based on \n[push2-python](https://github.com/ffont/push2-python). `push2-python` requires [pyusb](https://github.com/pyusb/pyusb) \nwhich is based in [libusb](https://libusb.info/). You'll most probably need to manually install `libusb` for your \noperative system if `pip install -r requirements.txt` does not do it for you. Moreover, to draw on Push2's screen, \nPush2Controller uses [`pycairo`](https://github.com/pygobject/pycairo) Python package. You'll most probably also \nneed to install [`cairo`](https://www.cairographics.org/) if `pip install -r requirements.txt` does not do it for \nyou (see [this page](https://pycairo.readthedocs.io/en/latest/getting_started.html) for info on that).\n\n**NOTE**: if running Push2Controller in macOS, there seem to be compatibility issues with Python versions other than\n3.8 so please use that Python version :).\n\nHere are some screenshots of Push2Controller and Shepherd running using a real Push2 device:\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"docs/ss_session_mode_playing.png\"/\u003e\nSession mode\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"docs/ss_melodic_mode.png\"/\u003e\nMelodic mode\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"docs/ss_clip_edit.png\"/\u003e\nClip edit mode\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"docs/ss_note_edit.png\"/\u003e\nNote edit mode\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"docs/ss_generator.png\"/\u003e\nGenerator mode\n\u003c/p\u003e\n\n\n\n\n#### Local development with Push2 simulator\n\nThe Push2Controller script initializes a Push2 simulator that can be used for development without the actual Push2 \ndevice being connected. While running the script, you can open the simulator by pointing your browser at `localhost:6128`.\nIf running the backend in Debug mode, a window will automatically be opened which will run a simple web browser loading\n`localhost:6128` so you don't need to manually open your browser. Here is a screenshot of the simulator in action:\n\n![simulator_screenshot](https://user-images.githubusercontent.com/478615/208401787-9c055069-9904-4f10-9cd1-6b065b762e37.png)\n\n\n#### Push2Controller device definition files\n\nTODO\n\n\n### pyshepherd\n\nA Pythong package independent of Push2Controller is provided to develop Python-based apps that interact with Shepherd's\nbackend. All you need to do is to create a class that inherits from `pyshepherd.ShepherdBackendControllerApp` and\nimplement some abstract methods. Below is an example of a very simple testing app. `pyshepherd`'s docstrings (and the\nexamples provided in Push2Controller) should hopefully be enough to get you started using `pyshepherd` and making your\nown Shepherd controller script.\n\n````python\nfrom pyshepherd.pyshepherd import ShepherdBackendControllerApp\nimport time\n\n\nclass App(ShepherdBackendControllerApp):\n\n    def on_state_first_synced(self):\n        # Create new empty session when  we first sync with backend\n        self.session.new(num_tracks=2, num_scenes=1)\n\n    def on_new_session_loaded(self):\n        # When the session has been loaded, add events to some clips and play them\n        clip = self.session.tracks[0].clips[0]\n        clip.clear()\n        clip.add_sequence_note_event(60, 1.0, 0.0, 0.5)\n        clip.add_sequence_note_event(61, 1.0, 0.5, 0.5)\n        clip.add_sequence_note_event(62, 1.0, 1.0, 0.5)\n        clip.add_sequence_note_event(63, 1.0, 1.5, 0.5)\n        clip.set_length(2.0)\n        clip.play()\n\n        clip = self.session.tracks[1].clips[0]\n        clip.clear()\n        clip.add_sequence_note_event(62, 1.0, 0.0, 0.5)\n        clip.add_sequence_note_event(64, 1.0, 0.5, 0.5)\n        clip.add_sequence_note_event(66, 1.0, 1.0, 0.5)\n        clip.set_length(1.5)\n        clip.play()\n\n        self.session.play()\n\n    def on_state_update_received(self, update_data):\n        # Here we print state updates from Shepherd backend just to give an idea of the type of information that\n        # is being exchanged\n        print(update_data)\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        try:\n            while True:\n                time.sleep(1)\n        except KeyboardInterrupt:\n            if self.session is not None:\n                self.session.stop()\n\n\nif __name__ == \"__main__\":\n    # Start the app and indicate a port in which the \"state debugger\" should run. While your app is running, point your\n    # browser to http://localhost:5100 to see the whole Shepherd backend state as it has been synced with your \n    # controller script and converted to Python objects. This shows all the state information that is available to\n    # the controller script and that can be used to provide the user interface.\n    app = App(debugger_port=5100)\n````\n\n\n## Deploying Shepherd backend and Push2Controller in a Raspberry Pi\n\n**NOTE**: All instructions below assume you have ssh connection with the Raspberry Pi. Here are the instructions \nfor [enabling ssh](https://www.raspberrypi.org/documentation/remote-access/ssh/) on the Pi. Here are instructions \nfor [setting up wifi networks](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md). \nAlso, here are instructions for [changing the hostname](https://thepihut.com/blogs/raspberry-pi-tutorials/19668676-renaming-your-raspberry-pi-the-hostname) \nof the Pi so for example you can access it like `ssh pi@shepherd`.\n\n### Deploying Shepherd backend on Raspberry Pi\n\nTo run Shepherd on the Rapsberry Pi you need yo use `xvfb` to avoid window errors. This needs to be revised as this dependency can probably be removed quite easily. Use the following command to use Shepherd:\n\n```\nxvfb-run -a /home/pi/shepherd/Shepherd/Builds/LinuxMakefile/build/Shepherd\n```\n\nAlternatively, install following `systemd` service at `/lib/systemd/system/shepherd.service` (change paths is accordingly):\n\n```\n[Unit]\nDescription=shepherd\nAfter=network-online.target\n\n[Service]\nType=simple\nWorkingDirectory=/home/pi/shepherd/\nExecStart=xvfb-run -a /home/pi/shepherd/Shepherd/Builds/LinuxMakefile/build/Shepherd\nUser=pi\n\n[Install]\nWantedBy=multi-user.target\n```\n\nThen you can enable the service...\n\n```\nsudo systemctl enable shepherd\n```\n\n...and start/stop/restart it with:\n\n```\nsudo systemctl start shepherd\nsudo systemctl stop shepherd\nsudo systemctl restart shepherd\n```\n\nUsing that service configured, Shepherd will automatically be started after Raspberry Pi boots.\n\nWhen running as a servie, check stdout with:\n\n```\nsudo journalctl -fu shepherd\n```\n\n### Deploying Push2Controller on Raspberry Pi\n\nTo run Shepherd Controller on the Rapsberry Pi you need to install Python requirements as described above. Then, a `systemd` service should be configured so that Shepherd Controller is run together with Shepherd. Create a file at `/lib/systemd/system/shepherd_cotroller.service` (change paths is accordingly):\n\nThese are instructions to get Shepherd Controller running on a Rapsberry Pi and load at startup. \n\n1. Install system dependencies\n```\nsudo apt-get update \u0026\u0026 sudo apt-get install -y libusb-1.0-0-dev libcairo2-dev python3 python3-pip git libasound2-dev libatlas-base-dev\n```\n\n2. Clone the app repository\n```\ngit clone https://github.com/ffont/shepherd.git\n```\n\n3. Install Python dependencies\n```\ncd shepherd\npip3 install -r requirements.txt\n```\n\n4. Configure permissions for using libusb without sudo (untested with these specific commands, but should work)\n\nCreate a file in `/etc/udev/rules.d/50-push2.rules`...\n\n    sudo nano /etc/udev/rules.d/50-push2.rules\n\n...with these contents:\n\n    add file contents: SUBSYSTEM==\"usb\", ATTR{idVendor}==\"2982\", ATTR{idProduct}==\"1967\", GROUP=\"audio\"\n\nThen run:\n\n    sudo udevadm control --reload-rules\n    sudo udevadm trigger\n\n\n5. Configure Python script to run at startup:\n\nCreate file...\n\n    sudo nano /lib/systemd/system/shepherd_controller.service\n\n...with these contents:\n\n```\n[Unit]\nDescription=shepherd_controller\nAfter=network-online.target\n\n[Service]\nWorkingDirectory=/home/pi/shepherd/Controller\nExecStart=/usr/bin/python3 app.py                                                \nStandardOutput=syslog\nUser=pi\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\n```\n\nThen you can enable the service...\n\n```\nsudo systemctl enable shepherd_controller\n```\n\n...and start/stop/restart it with:\n\n```\nsudo systemctl start shepherd_controller\nsudo systemctl stop shepherd_controller\nsudo systemctl restart shepherd_controller\n```\n\nUsing that service configured, Shepherd Controller will automatically be started after Raspberry Pi boots.\n\nWhen running as a servie, check stdout with:\n\n```\nsudo journalctl -fu shepherd_controller\n```\n\n\n## License\n\nShepherd is released under the **GPLv3** open source software license \n(see [LICENSE](https://github.com/ffont/shepherd/blob/master/LICENSE) file) with the code being available \nat [https://github.com/ffont/shepherd](https://github.com/ffont/shepherd). Source uses the following open source \nsoftware libraries: \n\n* [juce](https://juce.com), available under GPLv3 license ([@2f98020](https://github.com/juce-framework/JUCE/tree/2f980209cc4091a4490bb1bafc5d530f16834e58), v6.1.6)\n* [asio](https://github.com/chriskohlhoff/asio), available under Boost Software License] ([@f0a1e1c](https://github.com/chriskohlhoff/asio/tree/f0a1e1c7c0387ad16358c81eb52528f190df625c))\n* [Simple-WebSocket-Server](https://gitlab.com/eidheim/Simple-WebSocket-Server), available under MIT license ([@293a407](https://gitlab.com/eidheim/Simple-WebSocket-Server/-/tree/293a407f39fe50e285c8599b3d98a7da25371d20))\n* [source](https://github.com/ffont/source), available under GPLv3 license ([@ae89f3a](https://github.com/ffont/source/commit/ae89f3a8d48f461a5045fa45ed256637c62825ca)) - Only required if enabling the \"sampler\" mode\n* [ff_meters](https://github.com/ffAudio/ff_meters), available under BSD 3 clause license ([@968bb8e](https://github.com/ffAudio/ff_meters/tree/968bb8e00c5e47aaf18b388341493edc771a088f) - Only required if enabling the \"sampler\" mode\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffont%2Fshepherd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fffont%2Fshepherd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffont%2Fshepherd/lists"}