# FCB1010 MIDI Integration Technical Reference

## 1. MIDI Controller Configuration

The FCB1010 will be configured with a consistent set of Control Change (CC) messages for all buttons and pedals:

| Control | CC Number | Value | Description |
|---------|-----------|-------|-------------|
| **Button 1** | CC 1 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 2** | CC 2 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 3** | CC 3 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 4** | CC 4 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 5** | CC 5 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 6** | CC 6 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 7** | CC 7 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 8** | CC 8 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 9** | CC 9 | 127/0 | Value 127 when pressed, 0 when released |
| **Button 10** | CC 10 | 127/0 | Value 127 when pressed, 0 when released |
| **UP** | CC 11 | 127/0 | Value 127 when pressed, 0 when released |
| **DOWN** | CC 12 | 127/0 | Value 127 when pressed, 0 when released |
| **Expression A** | CC 16 | 0-127 | Continuous controller |
| **Expression B** | CC 17 | 0-127 | Continuous controller |
| **MIDI Channel** | All on Channel 1 | | Single channel for simplicity |

## 2. System Architecture

### 2.1 Integration Diagram

```
+-------------+     +----------------+     +-------------+     +--------------+
| JACK Thread | --> | Lock-free MIDI | --> | MIDI Thread | --> | Application  |
| (real-time) |     | Input Queue    |     |             |     | Logic Thread |
+-------------+     +----------------+     +-------------+     +--------------+
       ^                                         |
       |                                         v
+----------------+                        +----------------+
| Lock-free MIDI |                        | Configuration  |
| Output Queue   | <----------------------| Commands       |
+----------------+                        +----------------+
```

### 2.2 Communication Channels

The system uses Crossbeam channels for thread communication:

1. **MIDI Input Channel**: Transfers raw MIDI data from JACK thread to MIDI processing thread
2. **MIDI Output Channel**: Transfers SysEx configuration messages from MIDI thread to JACK thread
3. **Event Channel**: Delivers controller events from MIDI thread to application logic
4. **Command Channel**: Sends configuration commands from application to MIDI thread

### 2.3 MIDI Message Flow

1. **JACK Callback (Real-time Thread)**:
   - Receives MIDI data from FCB1010
   - Copies data to `midi_input_sender`
   - Reads from `midi_output_receiver` for SysEx configuration

2. **MIDI Processing Thread**:
   - Reads from `midi_input_receiver`
   - Translates MIDI messages to `ControllerEvent` instances
   - Sends events via `event_sender`
   - Processes configuration commands from `command_receiver`
   - Sends SysEx messages via `midi_output_sender`

3. **Application Logic Thread**:
   - Reads from `event_receiver`
   - Sends configuration commands via `command_sender`

## 3. Message Translation

### 3.1 MIDI to ControllerEvent Translation

The MIDI processing thread translates FCB1010 MIDI messages to controller-independent events according to the following mapping:

| MIDI Message | Condition | Translated Event |
|--------------|-----------|------------------|
| CC 1, Value 127 | Channel 1 | ButtonPress(1) |
| CC 2, Value 127 | Channel 1 | ButtonPress(2) |
| CC 3, Value 127 | Channel 1 | ButtonPress(3) |
| CC 4, Value 127 | Channel 1 | ButtonPress(4) |
| CC 5, Value 127 | Channel 1 | ButtonPress(5) |
| CC 6, Value 127 | Channel 1 | ButtonPress(6) |
| CC 7, Value 127 | Channel 1 | ButtonPress(7) |
| CC 8, Value 127 | Channel 1 | ButtonPress(8) |
| CC 9, Value 127 | Channel 1 | ButtonPress(9) |
| CC 10, Value 127 | Channel 1 | ButtonPress(10) |
| CC 11, Value 127 | Channel 1 | Navigation(NavigationButton::Up) |
| CC 12, Value 127 | Channel 1 | Navigation(NavigationButton::Down) |
| CC 16, Any Value | Channel 1 | ExpressionPedal(ExpressionPedal::A, value) |
| CC 17, Any Value | Channel 1 | ExpressionPedal(ExpressionPedal::B, value) |

Notes on translation:
- Only button press events (value 127) are translated for footswitches and navigation buttons
- Button release events (value 0) are ignored
- All expression pedal value changes (0-127) are translated
- Messages on MIDI channels other than Channel 1 are ignored
- Other MIDI message types (Program Change, Note On/Off, etc.) are ignored

### 3.2 Event Types

```rust
pub enum ControllerEvent {
    /// Footswitch button press (1-10)
    ButtonPress(u8),
    
    /// Navigation button press
    Navigation(NavigationButton),
    
    /// Expression pedal value change
    ExpressionPedal(ExpressionPedal, u8), // value 0-127
}

pub enum NavigationButton {
    Up,
    Down,
}

pub enum ExpressionPedal {
    A,
    B,
}

pub enum FcbCommand {
    /// Configure the FCB1010 for our application
    Initialize,
}
```

## 4. FCB1010 Initialization

The FCB1010 is configured at startup using SysEx messages:

```rust
fn initialize_fcb1010(command_sender: &crossbeam::channel::Sender<FcbCommand>) {
    // Send initialization command to MIDI processing thread
    command_sender.send(FcbCommand::Initialize).unwrap_or_else(|e| {
        error!("Failed to send FCB1010 initialization command: {}", e);
    });
}
```

The MIDI processing thread handles the initialization by sending SysEx messages:

```rust
fn handle_fcb_command(
    command: FcbCommand,
    midi_output_sender: &crossbeam::channel::Sender<Vec<u8>>
) {
    match command {
        FcbCommand::Initialize => {
            info!("Initializing FCB1010");
            
            // Get SysEx messages from FCB1010 SysEx generator
            let sysex_messages = generate_fcb1010_configuration();
            
            // Send each SysEx message with a delay to avoid buffer overruns
            for message in sysex_messages {
                midi_output_sender.send(message).unwrap_or_else(|e| {
                    error!("Failed to send SysEx message: {}", e);
                });
                
                // Allow time for the message to be processed
                std::thread::sleep(std::time::Duration::from_millis(50));
            }
            
            info!("FCB1010 initialization complete");
        }
    }
}
```

## 5. JACK Integration

### 5.1 JACK Process Callback

The JACK process callback runs in a real-time thread with strict timing constraints. To maintain real-time safety:

1. **No Memory Allocations**: The callback must never allocate memory (no `Vec`, `String`, `Box`, etc.)
2. **No Blocking Operations**: The callback must not block (no file I/O, mutex locks, etc.)
3. **Minimal Processing**: Only the bare minimum work should be done in this thread

For FCB1010 integration, the JACK callback should:

1. **Read MIDI Input**: Copy raw MIDI data bytes to a pre-allocated lock-free ring buffer
2. **Write MIDI Output**: Read from a lock-free buffer and send to the MIDI output port

#### Avoiding Allocations

To avoid allocations while handling MIDI data:

1. **Pre-allocated Buffers**: Use fixed-size arrays or pre-allocated ring buffers
2. **Zero-Copy Access**: Access MIDI data directly without copying when possible
3. **Message Passing**: Use lock-free data structures that don't require allocation
4. **Byte References**: Pass references to MIDI data rather than copying the data

### 5.2 MIDI Processing Thread

The MIDI processing thread runs continuously outside of JACK's real-time constraints, allowing for:

1. Receiving MIDI data from the lock-free input buffer
2. Translating MIDI messages to controller events
3. Sending events to the application logic
4. Processing configuration commands
5. Sending SysEx messages to the FCB1010

This thread can safely perform memory allocations and more complex processing since it's not subject to real-time constraints.

## 6. Testing Approach

### 6.1 Mock FCB Implementation

For testing without hardware, a mock FCB implementation will use the same MIDI message format as the physical FCB1010:

1. **JACK-Based MIDI Device**: The mock will appear as a standard MIDI device in the JACK system
2. **Message Format Consistency**: It will generate identical CC messages following the table in section 1
3. **Bidirectional Communication**: It will receive and verify SysEx configuration messages
4. **Programmatic Control**: It can be triggered by test code to simulate button presses and pedal movements

This approach allows testing the complete integration without requiring the physical FCB1010 hardware, while ensuring message format compatibility.

The mock FCB will translate controller-independent events back to MIDI messages, effectively doing the reverse of the translation described in section 3.1. This symmetrical translation enables comprehensive testing of the entire message pipeline.

### 6.2 Integration Testing

Integration tests will verify the complete flow from MIDI messages to application events:

1. Create a mock FCB instance
2. Start the MIDI processing thread
3. Generate MIDI messages from the mock FCB
4. Verify correct `ControllerEvent` instances are produced
5. Test error conditions and recovery

### 6.3 SysEx Testing

SysEx testing will verify the FCB1010 configuration messages:

1. Create a mock FCB that captures SysEx messages
2. Send the initialization command
3. Verify the SysEx messages match the expected format
4. Test with corrupted or incomplete SysEx responses

## 7. Logging

The integration will use the Rust `log` crate for detailed logging:

```rust
// MIDI message logging
debug!("Received MIDI message: {:?}", data);

// Controller event logging
info!("Translated to controller event: {:?}", event);

// SysEx logging
info!("Sending FCB1010 configuration SysEx");
debug!("SysEx message: {:?}", sysex_message);

// Error logging
error!("Failed to process MIDI message: {}", error);
```

Initial logs will go to standard output, with a future extension to log to a UI window.