# Routing MIDI Messages > Original: [Routing MIDI messages](https://tttapa.github.io/Control-Surface/Doxygen/d3/df7/midi-tutorial.html) ## Default routing `Control_Surface.begin()` automatically connects the default MIDI interface to all output and input elements. For single-interface projects, no manual routing is needed. ## MIDI Pipes Pipes connect sources to sinks. Use shift operators: ```cpp pico MIDI_PipeFactory<2> pipes; midi1 >> pipes >> midi2; // midi1 sends to midi2 midi2 >> pipes >> midi1; // midi2 sends to midi1 ``` ## Bidirectional pipes ```cpp pico BidirectionalMIDI_PipeFactory<1> bpipes; midi1 | bpipes | midi2; ``` ## Custom filtering Subclass `MIDI_Pipe` and override `mapForwardMIDI`: ```cpp pico struct ChannelFilter : MIDI_Pipe { Channel allowed; ChannelFilter(Channel ch) : allowed(ch) {} void mapForwardMIDI(ChannelMessage msg) override { if (msg.getChannel() == allowed) sourceMIDItoSink(msg); } void mapForwardMIDI(SysExMessage msg) override { sourceMIDItoSink(msg); } void mapForwardMIDI(SysCommonMessage msg) override { sourceMIDItoSink(msg); } void mapForwardMIDI(RealTimeMessage msg) override { sourceMIDItoSink(msg); } }; ChannelFilter ch1Only {Channel_1}; // midi >> ch1Only >> otherMidi; ``` ## Multi-interface example ```cpp pico #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include using namespace cs; BluetoothMIDI_Interface ble; USBMIDI_Interface usb; BidirectionalMIDI_PipeFactory<1> pipes; int main() { stdio_init_all(); if (cyw43_arch_init()) return 1; ble | pipes | usb; Control_Surface.begin(); while (true) { Control_Surface.loop(); sleep_ms(1); } } ```