5.6 KiB
5.6 KiB
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:
- Display connects to Unix socket
- Audio engine detects new connection
- Complete state dump sent immediately:
- 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_beatin 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
- If it's not a multiple of
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,
}
}