fcb_looper/interface_spec.md
2025-08-18 11:51:49 +02:00

5.6 KiB
Raw Permalink Blame History

FCB1010 Looper Pedal - Interface Specification

System Architecture Overview

graph TD
    FCB1010[FCB1010 MIDI Controller]
    UMC404HD[UMC404HD Audio Interface]

    JACK_MIDI[JACK MIDI]
    JACK_AUDIO[JACK Audio]
    AudioEngine[Audio Engine Process]
    Display[Display Process]

    FCB1010 <-->|MIDI DIN| UMC404HD

    UMC404HD <-->|MIDI USB| JACK_MIDI
    UMC404HD <-->|Audio USB| JACK_AUDIO

    JACK_MIDI -->|CC messages| AudioEngine
    AudioEngine -->|MIDI Clock/Click| JACK_MIDI

    JACK_AUDIO <-->|Audio Data| AudioEngine

    AudioEngine -->|OSC Unix Socket| Display
    
    subgraph "Hardware"
        FCB1010
        UMC404HD
    end
    
    subgraph "Software"
        JACK_MIDI
        JACK_AUDIO
        AudioEngine
        Display
    end

MIDI Interface

Input: FCB1010 → Audio Engine

Button Mappings (State-Independent)

Button 1:   CC #20  (Record/Arm / Tap Tempo)
Button 2:   CC #21  (Play/Mute Track / Click Toggle)  
Button 3:   CC #22  (Solo Track)  
Button 4:   CC #23  (Overdub)
Button 5:   CC #24  (Clear Track / Clear Column)
Button 6:   CC #25  (Column 1 Select)
Button 7:   CC #26  (Column 2 Select)
Button 8:   CC #27  (Column 3 Select)
Button 9:   CC #28  (Column 4 Select)
Button 10:  CC #29  (Column 5 Select)
UP:         CC #30  (Row Up / Mode Switch)
DOWN:       CC #31  (Row Down / Mode Switch)

Expression Pedals

Expression A: CC #1 (Track Volume / Click Volume)
Expression B: CC #7 (Master Volume)

Note: FCB1010 sends identical CC messages regardless of current system state. The Audio Engine interprets these based on its internal mode (Menu vs Performance).

Output: Audio Engine → External Devices

MIDI Clock (Continuous)

Clock (F8H): 24 PPQN, sent continuously while application running

Transport Control

Start (FAH): When application starts or BPM changes
Stop (FCH):  When application stops or BPM changes

Song Position Pointer

SPP (F2H): Reset to 0 on Start message
           Increments during playback
           Stops incrementing on Stop message
           1 MIDI beat = 6 MIDI clocks = 1/4 quarter note

OSC Interface (Audio Engine → Display)

Transport: Unix Domain Socket

  • Protocol: OSC 1.0 over SLIP-encoded stream
  • Direction: Unidirectional (Audio Engine → Display only)

Message Categories

1. System State Messages

/looper/mode <string>
   Values: "menu" | "performance"
   Update frequency: On change only

/looper/tempo <float>
   Range: 50.0 - 200.0 BPM
   Update frequency: On change only

/looper/click/enabled <int>
   Values: 0 (disabled) | 1 (enabled)
   Update frequency: On change only

/looper/click/volume <float>
   Range: 0.0 - 1.0
   Update frequency: On expression pedal change

/looper/master/volume <float>
   Range: 0.0 - 1.0
   Update frequency: On expression pedal change

2. Navigation State Messages

/looper/selected/column <int>
   Range: 1-5
   Update frequency: On change only

/looper/selected/row <int>
   Range: 1-5
   Update frequency: On change only

3. Matrix Cell State Messages

/looper/cell/<column>/<row>/state <string>
   Column: 1-5, Row: 1-5
   Values: "empty" | "loading" | "ready" | "recording" | "playing" | "solo"
   Update frequency: On change only

/looper/cell/<column>/<row>/volume <float>
   Column: 1-5, Row: 1-5
   Range: 0.0 - 1.0
   Update frequency: On change only

4. Column State Messages

/looper/column/<column>/beats <int>
   Column: 1-5
   Value: Number of beats in column (set by first recording, 0 = not set)
   Update frequency: On first recording in column

/looper/column/<column>/beat <int>
   Column: 1-5
   Value: Current beat (1 = start of loop, 1+ = beat N)
   Update frequency: On change

5. Metronome Messages

/looper/metronome/position <float>
   Range: 0.0 - 1.0 (position within current beat)
   Update frequency: same as PPQN midi signal

OSC Implementation Details

Initial State Synchronization

OSC is stateless - there's no "subscription" mechanism. When the display process connects:

  1. Display connects to Unix socket
  2. Audio engine detects new connection
  3. Complete state dump sent immediately:
  4. Regular updates begin (position updates, state changes)

OSC Message Bundling

For efficiency, column-beat messages are bundled:

Session Persistence

Single Source of Truth

  • Timing authority: samples_per_beat in state.json
  • Track existence: WAV file presence in filesystem
  • Tempo: Derived from (sample_rate × 60) ÷ samples_per_beat
  • Column beats: Derived from wav_length_samples ÷ samples_per_beat
  • Delete files:
    • If it's not a multiple of samples_per_beat
    • If it doesn't match the sample rate
    • When a track is cleared

Auto-Save Triggers

  • Track data changes (record/clear)
  • Tempo/timing changes
  • Volume adjustments (when constant for 5 seconds)
  • Application shutdown

Directory Structure

~/.fcb_looper/
   ├── state.json        # System state and timing authority
   ├── col_1_row_1.wav   # Audio tracks
   ├── col_1_row_2.wav
   └── ...

State File Format

{
  "version": "1.0",
  "connections": {
   "midi_in": [
      "sendmidi:midi_out"
   ],
   "audio_out": [
   ],
   "audio_in": [
   ]
  },
  "ui_state": {
    "selected_column": 3,
    "selected_row": 2
  },
  "user_preferences": {
    "click_enabled": true,
    "click_volume": 0.5,
    "master_volume": 0.8
  },
  "track_volumes": {
    "col_1_row_1": 0.75,
    "col_2_row_3": 0.9
  },
  "timing": {
    "sample_rate": 44100,
    "samples_per_beat": 105840,
  }
}