248 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			5.6 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)
 | ||
| ```
 | ||
| 
 | ||
| #### 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" | "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
 | ||
| 
 | ||
| ```osc
 | ||
| /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
 | ||
| 
 | ||
| ```osc
 | ||
| /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
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "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,
 | ||
|   }
 | ||
| }
 | ||
| ``` |