# Manual Test Protocols – Guitar / Audio Looper This document provides step‑by‑step manual testing procedures using a real guitar (or any line‑level mono audio source) with the `looper` engine. ## Prerequisites - A running JACK server (e.g. `jackd -d alsa -r 48000 -p 256`) - The looper binary compiled (`cd engine && make`) - An audio interface recognised by ALSA (or PulseAudio JACK bridge) - A guitar connected to your interface’s input - `qjackctl` (optional, for visual wiring) or knowledge of `jack_connect` commands ## Test 1 – Basic Audio Pass‑Through (Guitar Monitor) 1. Start the looper in a terminal: ```sh ./looper ``` 2. Launch `qjackctl` (or use `jack_connect` from shell) to view available ports. 3. Connect your interface’s capture port to the looper’s input: ```sh jack_connect system:capture_1 looper:input ``` 4. Connect the looper’s output to your interface playback ports: ```sh jack_connect looper:output system:playback_1 ``` 5. Pluck a few strings – you should hear your guitar coming through the looper immediately (channel 0 is in **IDLE** state, which passes input straight to output). 6. To stop, press `Ctrl+C` in the looper terminal. **Expected result**: You hear your guitar with no latency issues (depending on JACK buffer size). If you hear nothing, check port names with `jack_lsp`. --- ## Test 2 – Record a Short Loop (MIDI Control) ### 2a – Using MIDI keyboard (or a MIDI controller) 1. Start the looper as above. 2. Connect your MIDI controller to the looper’s control port: ```sh jack_connect :midi_out looper:control ``` Replace `` with the actual MIDI port name (use `jack_lsp` to find it). 3. Send **note 1** (velocity 127) to switch channel 0 into **RECORD** state. - On most keyboards, this is the C# key two octaves above middle C (MIDI note 1). Press it once. 4. Play your guitar for about 2 seconds. The looper is recording. 5. Press **note 1** again. The looper transitions to **LOOPING** state. The recorded 2‑second phrase starts playing back repeatedly. 6. You should hear the loop repeating. Pluck strings while the loop plays – the IDLE monitoring is still active on channel 0 (the loop is mixed with the live input). 7. Press **note 1** a third time to **PAUSE** the loop; press again to resume. ### 2b – Using FIFO commands (if you have no MIDI keyboard) 1. Start the looper. 2. Open a second terminal. 3. Send: ```sh echo "record 0" > /tmp/looper_cmd ``` 4. Play guitar for a few seconds. 5. Send again: ```sh echo "record 0" > /tmp/looper_cmd ``` 6. Loop should start repeating. Test pause by sending again (second command cycles IDLE→RECORD→LOOPING→PAUSED→…). **Expected result**: The loop repeats seamlessly. If you hold a chord while the loop is playing, the live input still passes through. --- ## Test 3 – Save the Loop to a WAV File 1. Ensure a loop is playing (LOOPING state) on channel 0. 2. Send the save command: ```sh echo "save" > /tmp/looper_cmd ``` or (MIDI) press control‑key (note 64) + note 71. 3. After a brief delay (the loop buffer is written synchronously), a file `save.wav` appears in the engine directory. 4. Check the file size is > 44 bytes and play it with any media player: ```sh aplay save.wav ``` **Expected result**: The saved file contains exactly what the looper was playing (your recorded guitar phrase). The RMS of the playback should be similar to the live signal. --- ## Test 4 – Load a WAV File into a Channel 1. Put a mono 16‑bit WAV file named `loop.wav` in the engine directory (e.g. a short drum loop or a guitar riff). 2. Start the looper and send the load command: ```sh echo "load" > /tmp/looper_cmd ``` or (MIDI) control‑key + note 70. 3. The loaded audio begins playing immediately on channel 0 (state = LOOPING). 4. Verify you hear the loop repeating. **Expected result**: The WAV is loaded and plays correctly. The loop length matches the duration of the file (up to `LOOP_BUF_SIZE` frames, default 8 seconds). --- ## Test 5 – Dynamic Channel Creation and Binding 1. Start the looper. 2. Add a second audio channel: ```sh echo "add" > /tmp/looper_cmd ``` 3. Check that new ports appear: ```sh jack_lsp | grep channel1 ``` 4. Bind the client to channel 1: ```sh echo "bind 1" > /tmp/looper_cmd ``` 5. Connect your guitar to both channels for stereo testing? Not necessary. But you can route differently. 6. Now when you send `record 1`, the bind ensures the command affects channel 1 instead of channel 0. 7. Repeat the record/loop process on channel 1, while channel 0 continues its own loop. **Expected result**: Two independent loops can play simultaneously without interfering. --- ## Test 6 – Scene Switching 1. Make sure a loop is playing on channel 0. 2. Add a second scene to channel 0: ```sh echo "scene_add" > /tmp/looper_cmd ``` (Only adds scene if `MAX_SCENES` not exceeded, default 4.) 3. Switch to the new scene: ```sh echo "scene_next" > /tmp/looper_cmd ``` The playback stops because the new scene is IDLE. 4. Record a different phrase on the new scene (send `record 0`). 5. Switch back to the first scene (`scene_prev`) – the original loop resumes. **Expected result**: Different independent loops in separate scenes; switching scenes does not lose previously recorded loops. --- ## Test 7 – MIDI Clock Sync If you have an external MIDI clock source (e.g. a drum machine or DAW sending MIDI start/stop): 1. Connect the clock source to `looper:clock` port. 2. Send MIDI Start (`0xFA`). The looper’s current scene (if IDLE) transitions to RECORD. 3. Send MIDI Stop (`0xFC`). The current scene goes IDLE (loop stops). 4. Send MIDI Continue (`0xFB`) while the scene is PAUSED – it resumes LOOPING. **Expected result**: Transport commands control looper state reliably. --- ## Test 8 – Edge Cases ### 8a – Rapid toggling Cycle the RECORD/LOOPING/PAUSED states many times in quick succession (send `record 0` every 200 ms for 5 seconds). The looper should not crash or produce glitches. ### 8b – Remove channel while playing Add a channel, start a loop on it, then remove the channel with: ```sh echo "remove" > /tmp/looper_cmd ``` The loop should stop gracefully after a one‑second grace period; the client should not crash. ### 8c – Save empty loop Attempt to `save` when the current scene is not LOOPING or loop_count == 0. No file should be created. The engine should log a message to stderr. --- ## Environment Variables - `LOOPER_CMD_FIFO` (overrides `/tmp/looper_cmd`) – useful for running multiple instances for testing. - `JACK_DEFAULT_SERVER` (JACK environment) – can be set to run a separate JACK server. --- ## Troubleshooting - **No audio after connection**: Ensure `jack_lsp` shows both source and destination ports, and that the looper is the only client using those ports. - **MIDI not recognised**: Verify that `midi_control_port` is created (`looper:control`). Use `jack_midi_dump` to see if note events arrive. - **“save.wav not created“** after save command: The scene must be in LOOPING state and `loop_count` > 0. Check the engine’s terminal output for error messages. --- ## Carla Plugin Management Manual Tests ### Test C1 – Load a plugin via colon command 1. Ensure the looper engine is running, and the client (`looper-client`) is also running. 2. In the client, enter colon mode (`:`) and type: ``` from looper:output ``` then press Enter. 3. Enter colon mode again and type: ``` to system:playback_1 ``` 4. Load a test LV2 plugin (e.g., /usr/lib/lv2/amsynth.lv2/amsynth.so): ``` addplugin /usr/lib/lv2/amsynth.lv2/amsynth.so ``` 5. The plugin should be loaded into Carla and its JACK ports are automatically connected (if `from` and `to` were set). You should see the plugin appear in the rack view when you press `R`. 6. Play some audio through the looper – it should be processed by the plugin. ### Test C2 – Toggle bypass 1. In rack view (`R`), select the plugin using `j`/`k`. 2. Press `b` or `B` to toggle bypass. 3. The effect should stop processing (bypass mode active); pressing again reactivates. ### Test C3 – Disconnect a plugin 1. In rack view, select the plugin. 2. Press `x` or `X` to disconnect all its JACK connections. 3. The plugin should no longer be connected to any looper ports; the audio should pass through unaffected. ### Test C4 – Unload a plugin 1. In rack view, select the plugin. 2. Press `d` or `D` to unload (remove) the plugin. 3. The plugin disappears from the rack list. ### Test C5 – Manual connection using colon commands 1. Set `from` and `to` ports as in Test C1. 2. Load a plugin without auto‑connection: - Do **not** set `from`/`to`, or set them after loading. - Use `addplugin` with only a path. 3. Manually connect ports in colon mode: ``` connect looper:output amsynth:in ``` The connection should be established. 4. Verify in `jack_lsp` that the ports are connected. ### Test C6 – Disconnect using colon commands 1. After a manual connection, disconnect using: ``` disconnect looper:output amsynth:in ``` 2. The ports should be disconnected. --- *Last updated:* 18 May 2026