240 lines
5.5 KiB
Markdown
240 lines
5.5 KiB
Markdown
# FCB1010 Looper Pedal - Interface Specification
|
||
|
||
## System Architecture Overview
|
||
|
||
```mermaid
|
||
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)
|
||
SysEx Test: CC #127 (Trigger FCB1010 reconfiguration)
|
||
```
|
||
|
||
#### 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 any column starts from all-stopped state
|
||
Stop (FCH): When all columns stop
|
||
```
|
||
|
||
#### 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
|
||
|
||
```osc
|
||
/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
|
||
|
||
```osc
|
||
/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
|
||
|
||
```osc
|
||
/looper/cell/<column>/<row>/state <string>
|
||
Column: 1-5, Row: 1-5
|
||
Values: "empty" | "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
|
||
|
||
```osc
|
||
/looper/column/<column>/bars <int>
|
||
Column: 1-5
|
||
Value: Number of bars in column (set by first recording, 0 = not set)
|
||
Update frequency: On first recording in column
|
||
|
||
/looper/column/<column>/bar <int>
|
||
Column: 1-5
|
||
Value: Current bar (1 = start of loop, 1+ = bar N)
|
||
Update frequency: On change
|
||
```
|
||
|
||
#### 5. Metronome Messages
|
||
|
||
```osc
|
||
/looper/metronome/position <float>
|
||
Range: 0.0 - 1.0 (position within current bar)
|
||
Update frequency: 60 FPS
|
||
```
|
||
|
||
### 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-bar messages are bundled:
|
||
|
||
## Session Persistence
|
||
|
||
**Single Source of Truth**
|
||
|
||
- **Timing authority**: `samples_per_bar` in state.json
|
||
- **Track existence**: WAV file presence in filesystem
|
||
- **Tempo**: Derived from `(sample_rate × 60) ÷ (samples_per_bar × beats_per_bar)`
|
||
- **Column bars**: Derived from `wav_length_samples ÷ samples_per_bar`
|
||
- **Delete files**:
|
||
- If it's not a multiple of `samples_per_bar`
|
||
- 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
|
||
|
||
```json
|
||
{
|
||
"version": "1.0",
|
||
"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_bar": 105840,
|
||
"time_signature": [4, 4]
|
||
}
|
||
}
|
||
``` |