diff --git a/docs/01-getting-started/_index.md b/docs/01-getting-started/_index.md deleted file mode 100644 index 1970a97..0000000 --- a/docs/01-getting-started/_index.md +++ /dev/null @@ -1,12 +0,0 @@ -# Getting Started - -cs-midi is a standalone MIDI library for pico-sdk, extracted from [Control Surface](https://github.com/tttapa/Control-Surface). It provides BLE MIDI, Classic BT SPP MIDI, rotary encoders, buttons, potentiometers, LEDs, banks, and a flexible pipe-based routing system. - -## What's included - -- **BLE MIDI** via BTstack (pico-native, no Arduino) -- **Output elements**: NoteButton, CCRotaryEncoder, CCPotentiometer, and more -- **Input elements**: NoteValue, CCValue, PBValue, LEDs -- **Pipe routing**: bidirectional MIDI pipes with filter/transform support -- **Banks**: switch between multiple CC/note mappings -- **Custom hooks**: extend the library without modifying it diff --git a/docs/01-getting-started/installation.md b/docs/01-getting-started/installation.md deleted file mode 100644 index addb68a..0000000 --- a/docs/01-getting-started/installation.md +++ /dev/null @@ -1,33 +0,0 @@ -# Installation - -## Prerequisites - -- [pico-sdk](https://github.com/raspberrypi/pico-sdk) (v2.0+) -- CMake 3.13+ -- ARM GCC toolchain - -## Adding to your project - -Add cs-midi as a git submodule: - -```bash -git submodule add https://git.else-if.org/jess/cs-midi.git lib/cs-midi -``` - -In your `CMakeLists.txt`: - -```cmake -add_subdirectory(lib/cs-midi) -target_link_libraries(your_target cs_midi) -target_include_directories(cs_midi PRIVATE ${CMAKE_CURRENT_LIST_DIR}) -``` - -The last line is required so cs-midi can find your project's `btstack_config.h` and `lwipopts.h`. - -## Include - -```cpp -#include -``` - -This single header pulls in everything: output elements, input elements, pipes, banks, BLE interface, and the Control Surface singleton. diff --git a/docs/_index.md b/docs/_index.md new file mode 100644 index 0000000..eff92c1 --- /dev/null +++ b/docs/_index.md @@ -0,0 +1,42 @@ +# cs-midi + +A standalone pico-sdk extraction of [tttapa/Control-Surface](https://github.com/tttapa/Control-Surface) (GPL-3.0). + +cs-midi provides the core MIDI element system, BLE MIDI transport, banks, selectors, and the declarative `Control_Surface` singleton for use with the Raspberry Pi Pico SDK and the CYW43 radio module (BTstack BLE backend). + +## Getting Started + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` + +## Differences from Control Surface + +- `#include ` replaces `#include ` +- `cs::BluetoothMIDI_Interface` replaces `USBMIDI_Interface` +- Standard `main()` with `cyw43_arch_init()` replaces Arduino `setup()`/`loop()` +- All types live in the `cs::` namespace +- No `MCU::` namespace — use raw CC numbers or `MIDI_CC::` constants + +## Credits + +Original library: [Control Surface](https://github.com/tttapa/Control-Surface) by **Pieter P (tttapa)** (GPL-3.0). +pico-sdk port: [pszsh](https://else-if.org). diff --git a/docs/book.yaml b/docs/book.yaml index f2e7758..a5c40e2 100644 --- a/docs/book.yaml +++ b/docs/book.yaml @@ -1,2 +1,2 @@ title: cs-midi -author: jess +author: Pieter P (tttapa) — pico-sdk port diff --git a/docs/classes.md b/docs/classes.md new file mode 100644 index 0000000..d4a2af5 --- /dev/null +++ b/docs/classes.md @@ -0,0 +1,264 @@ +# Class Reference + +Cross-reference between cs-midi and the original [Control Surface](https://tttapa.github.io/Control-Surface/Doxygen/annotated.html) library. + +## Ported Classes + +These classes are available in cs-midi and work identically to their Control Surface equivalents (within the `cs::` namespace unless noted). + +### MIDI Output Elements + +| Class | Template | Description | +|-------|----------|-------------| +| `NoteButton` | | Note On/Off on button press/release | +| `NoteButtonLatched` | | Toggle Note On/Off on each press | +| `NoteButtonLatching` | | Note On while held, toggles | +| `NoteChordButton` | | Chord (multiple notes) on press | +| `NoteButtons` | `` | Array of sequential note buttons | +| `NoteButtonMatrix` | `` | Row/column scanned note grid | +| `CCButton` | | CC 127/0 on press/release | +| `CCButtonLatched` | | Toggle CC 127/0 on each press | +| `CCButtonLatching` | | CC 127 while held, toggles | +| `CCButtons` | `` | Array of sequential CC buttons | +| `CCButtonMatrix` | `` | Row/column scanned CC grid | +| `CCPotentiometer` | | Analog input to CC 0-127 | +| `PBPotentiometer` | | Analog input to 14-bit Pitch Bend | +| `CCRotaryEncoder` | | Relative CC from encoder | +| `BorrowedCCRotaryEncoder` | | Shared encoder reference for CC | +| `CCAbsoluteEncoder` | | Absolute CC from encoder position | +| `PBAbsoluteEncoder` | | 14-bit Pitch Bend from encoder | +| `CCIncrementDecrementButtons` | | Two buttons for CC inc/dec + reset | +| `PCButton` | | Program Change on press | +| `ProgramChanger` | `` | Selectable program change list | + +### MIDI Input Elements + +| Class | Template | Description | +|-------|----------|-------------| +| `NoteValue` | | Incoming Note value (8-bit) | +| `CCValue` | | Incoming CC value (8-bit) | +| `KPValue` | | Incoming Key Pressure value (8-bit) | +| `PBValue` | | Incoming Pitch Bend value (14-bit) | +| `NoteRange` | `` | Array of incoming Note values | +| `CCRange` | `` | Array of incoming CC values | +| `KPRange` | `` | Array of incoming Key Pressure values | +| `NoteLED` | | LED driven by Note On/Off | +| `CCLED` | | LED driven by CC value | +| `KPLED` | | LED driven by Key Pressure | + +### Bankable Input Elements + +| Class | Template | Description | +|-------|----------|-------------| +| `Bankable::NoteValue` | `` | Bank-switched Note value | +| `Bankable::CCValue` | `` | Bank-switched CC value | +| `Bankable::KPValue` | `` | Bank-switched Key Pressure value | +| `Bankable::PBValue` | `` | Bank-switched Pitch Bend value | +| `Bankable::NoteLED` | `` | Bank-switched Note LED | +| `Bankable::CCLED` | `` | Bank-switched CC LED | +| `Bankable::KPLED` | `` | Bank-switched Key Pressure LED | + +### Banks and Selectors + +| Class | Template | Description | +|-------|----------|-------------| +| `Bank` | `` | N-setting bank for bankable elements | +| `Transposer` | `` | Note transposition bank | +| `OutputBank` | | Bank for output elements | +| `EncoderSelector` | `` | Bank selection via rotary encoder | +| `IncrementSelector` | `` | Bank selection via single button | +| `IncrementDecrementSelector` | `` | Bank selection via two buttons | +| `ManyButtonsSelector` | `` | Bank selection via N buttons | +| `SwitchSelector` | | Two-state selector from switch | +| `ProgramChangeSelector` | `` | Bank selection via incoming MIDI PC | +| `EncoderSelectorLEDs` | `` | EncoderSelector with LED indicators | +| `IncrementSelectorLEDs` | `` | IncrementSelector with LED indicators | +| `IncrementDecrementSelectorLEDs` | `` | IncrementDecrementSelector with LEDs | +| `ManyButtonsSelectorLEDs` | `` | ManyButtonsSelector with LEDs | +| `SwitchSelectorLED` | | SwitchSelector with LED | +| `ProgramChangeSelectorLEDs` | `` | ProgramChangeSelector with LEDs | + +### MIDI Interfaces + +| Class | Template | Description | +|-------|----------|-------------| +| `BluetoothMIDI_Interface` | | BLE MIDI via CYW43 BTstack | + +### MIDI Routing + +| Class | Template | Description | +|-------|----------|-------------| +| `MIDI_Pipe` | | Connects a MIDI source to a sink | +| `MIDI_PipeFactory` | `` | Creates N unidirectional pipes | +| `MIDI_Sink` | | Base class for MIDI receivers | +| `MIDI_Source` | | Base class for MIDI senders | + +### Hardware Utilities (`AH::` namespace) + +| Class | Template | Description | +|-------|----------|-------------| +| `Button` | | Debounced button with state machine | +| `IncrementButton` | | Button with auto-repeat | +| `IncrementDecrementButtons` | | Button pair with auto-repeat | +| `ButtonMatrix` | `` | Row/column button scanner | +| `GenericFilteredAnalog` | `<...>` | EMA-filtered analog input with hysteresis | +| `AHEncoder` | | Interrupt-driven quadrature encoder | + +### Infrastructure + +| Class | Description | +|-------|-------------| +| `Control_Surface_` | Singleton coordinating all elements (`Control_Surface.begin()` / `.loop()`) | +| `MIDIAddress` | Note/CC address with channel and cable | +| `MIDIChannelCable` | Channel + cable pair | +| `RelativeMIDIAddress` | Relative address offset | +| `Channel` | MIDI channel (1-16) | +| `Cable` | MIDI cable number | +| `DigitalCCSender` | Sends CC 0/127 | +| `ContinuousCCSender` | Sends CC 0-127 | +| `ContinuousCCSender14` | Sends 14-bit CC | +| `DigitalNoteSender` | Sends Note On/Off | +| `RelativeCCSender` | Sends relative CC (Mackie, etc.) | +| `PitchBendSender` | Sends Pitch Bend | +| `ProgramChangeSender` | Sends Program Change | + +--- + +## Not Yet Ported + +These classes exist in the original Control Surface but are not yet available in cs-midi. + +### Bankable Output Elements + +The entire bankable output layer (Phase 11) has not been extracted. This includes bank-switched versions of every output element. + +| Class | Original | Priority | +|-------|----------|----------| +| `Bankable::NoteButton` | Bankable note button | High | +| `Bankable::CCButton` | Bankable CC button | High | +| `Bankable::CCPotentiometer` | Bankable CC pot | High | +| `Bankable::CCRotaryEncoder` | Bankable CC encoder | High | +| `Bankable::CCAbsoluteEncoder` | Bankable absolute encoder | Medium | +| `Bankable::PBAbsoluteEncoder` | Bankable PB encoder | Medium | +| `Bankable::PBPotentiometer` | Bankable PB pot | Medium | +| `Bankable::PCButton` | Bankable program change button | Medium | +| `Bankable::NoteButtonLatched` | Bankable latched note | Low | +| `Bankable::NoteButtonLatching` | Bankable latching note | Low | +| `Bankable::CCButtonLatched` | Bankable latched CC | Low | +| `Bankable::CCButtonLatching` | Bankable latching CC | Low | +| `Bankable::NoteButtons` | Bankable note button array | Low | +| `Bankable::CCButtons` | Bankable CC button array | Low | +| `Bankable::NoteButtonMatrix` | Bankable note matrix | Low | +| `Bankable::CCButtonMatrix` | Bankable CC matrix | Low | +| `Bankable::NoteChordButton` | Bankable chord button | Low | +| `Bankable::CCIncrementDecrementButtons` | Bankable inc/dec | Low | +| `Bankable::CCSmartPotentiometer` | Smart pot (avoids bank-switch jumps) | Medium | +| `Bankable::PBSmartPotentiometer` | Smart PB pot | Medium | + +### Bankable ManyAddresses Output Elements + +Per-bank explicit address lists (alternative to offset-based banking). + +| Class | Original | +|-------|----------| +| `Bankable::ManyAddresses::NoteButton` | Per-bank note addresses | +| `Bankable::ManyAddresses::CCButton` | Per-bank CC addresses | +| `Bankable::ManyAddresses::CCPotentiometer` | Per-bank CC pot addresses | +| `Bankable::ManyAddresses::CCRotaryEncoder` | Per-bank CC encoder addresses | +| `Bankable::ManyAddresses::CCAbsoluteEncoder` | Per-bank absolute encoder addresses | +| `Bankable::ManyAddresses::PBAbsoluteEncoder` | Per-bank PB encoder addresses | +| `Bankable::ManyAddresses::PBPotentiometer` | Per-bank PB pot addresses | +| `Bankable::ManyAddresses::PCButton` | Per-bank PC addresses | +| `Bankable::ManyAddresses::NoteButtonMatrix` | Per-bank note matrix | +| `Bankable::ManyAddresses::CCButtonMatrix` | Per-bank CC matrix | +| `Bankable::ManyAddresses::CCIncrementDecrementButtons` | Per-bank inc/dec | + +### MCU (Mackie Control Universal) + +Full Mackie Control protocol support — VU meters, V-Pots, LCD, time display, etc. + +| Class | Description | +|-------|-------------| +| `MCU::VU` | VU meter input element | +| `MCU::VULEDs` | VU meter with LED output | +| `MCU::VPotRing` | V-Pot ring value reader | +| `MCU::VPotRingLEDs` | V-Pot ring with LED output | +| `MCU::LCD` | 112-char LCD display reader | +| `MCU::SevenSegmentDisplay` | 7-segment display driver | +| `MCU::TimeDisplay` | Time code display | +| `MCU::AssignmentDisplay` | Assignment display | +| `MCU::Bankable::VU` | Bankable VU meter | +| `MCU::Bankable::VULEDs` | Bankable VU with LEDs | +| `MCU::Bankable::VPotRing` | Bankable V-Pot ring | +| `MCU::Bankable::VPotRingLEDs` | Bankable V-Pot ring with LEDs | + +### USB MIDI + +| Class | Description | +|-------|-------------| +| `USBMIDI_Interface` | USB MIDI device interface | +| `USBHostMIDI_Interface` | USB Host MIDI interface | +| `GenericUSBMIDI_Interface` | Configurable USB MIDI backend | +| `USBDebugMIDI_Interface` | Serial monitor debug output | + +### Serial MIDI + +| Class | Description | +|-------|-------------| +| `HardwareSerialMIDI_Interface` | 5-pin DIN MIDI over UART | +| `SoftwareSerialMIDI_Interface` | Software serial MIDI | +| `HairlessMIDI_Interface` | Hairless MIDI serial bridge | + +### LED Bars and PWM + +| Class | Description | +|-------|-------------| +| `NoteCCKPLEDBar` | LED bar graph driven by MIDI | +| `NoteCCKPLEDPWM` | PWM LED brightness by velocity | +| `Bankable::NoteCCKPLEDBar` | Bankable LED bar | +| `Bankable::NoteCCKPLEDPWM` | Bankable PWM LED | + +### FastLED (Addressable LEDs) + +| Class | Description | +|-------|-------------| +| `NoteCCKPRangeFastLED` | Addressable LED strip driven by MIDI | +| `Bankable::NoteCCKPRangeFastLED` | Bankable variant | + +### Extended I/O Hardware + +| Class | Description | +|-------|-------------| +| `AH::AnalogMultiplex` | CD74HC4067 / CD74HC4051 multiplexer | +| `AH::ShiftRegisterOut` | 74HC595 shift register output | +| `AH::SPIShiftRegisterOut` | SPI-based shift register | +| `AH::ShiftRegisterOutRGB` | RGB LED shift register | +| `AH::MAX7219` | MAX7219 LED driver | +| `AH::MAX7219SevenSegmentDisplay` | MAX7219 7-segment display | +| `AH::LEDs` | Array of simple LEDs | +| `AH::DotBarDisplayLEDs` | Dot/bar mode LED array | +| `AH::MultiPurposeButton` | Long press / double press detection | +| `AH::RegisterEncoders` | Multiple encoders via registers | + +### Display + +| Class | Description | +|-------|-------------| +| `DisplayElement` | Base for on-screen elements | +| `DisplayInterface` | Abstract display driver | +| `SSD1306_DisplayInterface` | SSD1306 OLED driver | +| `BitmapDisplay` | Bitmap rendering on display | + +### Audio + +| Class | Description | +|-------|-------------| +| `AudioVU` | Audio level analysis | +| `AudioVULEDs` | Audio VU with LED output | +| `VolumeControl` | Audio volume knob | + +### Motor Fader + +| Class | Description | +|-------|-------------| +| `MotorFader` | Motorized fader with touch sense | diff --git a/docs/examples/01-output/01-note-button.md b/docs/examples/01-output/01-note-button.md new file mode 100644 index 0000000..ddb069d --- /dev/null +++ b/docs/examples/01-output/01-note-button.md @@ -0,0 +1,30 @@ +# NoteButton + +Sends Note On/Off on button press/release. + +> Original: `NoteButton.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button { + 5, // push button on GPIO 5 + {MIDI_Notes::C[4], Channel_1}, // note C4, channel 1 +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/02-cc-button.md b/docs/examples/01-output/02-cc-button.md new file mode 100644 index 0000000..4aedaca --- /dev/null +++ b/docs/examples/01-output/02-cc-button.md @@ -0,0 +1,30 @@ +# CCButton + +Sends CC 127 on press, CC 0 on release. + +> Original: `CCButton.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButton button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/03-pc-button.md b/docs/examples/01-output/03-pc-button.md new file mode 100644 index 0000000..4de08eb --- /dev/null +++ b/docs/examples/01-output/03-pc-button.md @@ -0,0 +1,30 @@ +# PCButton + +Sends Program Change on button press. + +> Original: `PCButton.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PCButton pcBtn { + 2, + {MIDI_PC::Steel_Drums, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/04-note-chord-button.md b/docs/examples/01-output/04-note-chord-button.md new file mode 100644 index 0000000..a26bbd1 --- /dev/null +++ b/docs/examples/01-output/04-note-chord-button.md @@ -0,0 +1,37 @@ +# NoteChordButton + +Plays a chord on button press. + +> Original: `NoteChordButton.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +constexpr Channel channel = Channel_1; + +NoteChordButton buttons[] { + {2, {MIDI_Notes::C[4], channel}, Bass::Double + Chords::Major}, + {3, {MIDI_Notes::D[4], channel}, Bass::Double + Chords::Minor}, + {4, {MIDI_Notes::E[4], channel}, Bass::Double + Chords::Minor}, + {5, {MIDI_Notes::F[4], channel}, Bass::Double + Chords::MajorFirstInv}, + {6, {MIDI_Notes::G[4], channel}, Bass::Double + Chords::MajorSecondInv}, + {7, {MIDI_Notes::A[4], channel}, Bass::Double + Chords::MinorSecondInv}, + {8, {MIDI_Notes::B[4], channel}, Bass::Double + Chords::Diminished}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/05-note-button-latched.md b/docs/examples/01-output/05-note-button-latched.md new file mode 100644 index 0000000..bde21b6 --- /dev/null +++ b/docs/examples/01-output/05-note-button-latched.md @@ -0,0 +1,28 @@ +# NoteButtonLatched + +First press sends Note On, second press sends Note Off. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonLatched button { + 5, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/06-note-button-latching.md b/docs/examples/01-output/06-note-button-latching.md new file mode 100644 index 0000000..6df821e --- /dev/null +++ b/docs/examples/01-output/06-note-button-latching.md @@ -0,0 +1,28 @@ +# NoteButtonLatching + +Note On while held, Note Off on release; toggles state. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonLatching button { + 5, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/07-note-buttons.md b/docs/examples/01-output/07-note-buttons.md new file mode 100644 index 0000000..f510c2a --- /dev/null +++ b/docs/examples/01-output/07-note-buttons.md @@ -0,0 +1,29 @@ +# NoteButtons + +Multiple note buttons with sequential addresses. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtons<4> buttons { + {2, 3, 4, 5}, // GPIO pins + {MIDI_Notes::C[4], Channel_1}, // base address + 1, // increment between addresses +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/08-note-button-matrix.md b/docs/examples/01-output/08-note-button-matrix.md new file mode 100644 index 0000000..97da84c --- /dev/null +++ b/docs/examples/01-output/08-note-button-matrix.md @@ -0,0 +1,35 @@ +# NoteButtonMatrix + +Grid of note buttons using row/column scanning. + +> Original: `NoteButtonMatrix.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonMatrix<2, 3> matrix { + {0, 1}, // row pins + {2, 3, 4}, // column pins + {{ + {MIDI_Notes::C[4], MIDI_Notes::D[4], MIDI_Notes::E[4]}, + {MIDI_Notes::F[4], MIDI_Notes::G[4], MIDI_Notes::A[4]}, + }}, + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/09-cc-button-latched.md b/docs/examples/01-output/09-cc-button-latched.md new file mode 100644 index 0000000..75f2dd9 --- /dev/null +++ b/docs/examples/01-output/09-cc-button-latched.md @@ -0,0 +1,28 @@ +# CCButtonLatched + +First press sends CC 127, second press sends CC 0. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonLatched button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/10-cc-button-latching.md b/docs/examples/01-output/10-cc-button-latching.md new file mode 100644 index 0000000..7c605f3 --- /dev/null +++ b/docs/examples/01-output/10-cc-button-latching.md @@ -0,0 +1,28 @@ +# CCButtonLatching + +CC 127 while held, CC 0 on release; toggles state. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonLatching button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/11-cc-buttons.md b/docs/examples/01-output/11-cc-buttons.md new file mode 100644 index 0000000..f6598b9 --- /dev/null +++ b/docs/examples/01-output/11-cc-buttons.md @@ -0,0 +1,29 @@ +# CCButtons + +Multiple CC buttons with sequential addresses. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtons<4> buttons { + {2, 3, 4, 5}, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, + 1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/12-cc-button-matrix.md b/docs/examples/01-output/12-cc-button-matrix.md new file mode 100644 index 0000000..5824146 --- /dev/null +++ b/docs/examples/01-output/12-cc-button-matrix.md @@ -0,0 +1,33 @@ +# CCButtonMatrix + +Grid of CC buttons using row/column scanning. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonMatrix<2, 3> matrix { + {0, 1}, // row pins + {2, 3, 4}, // column pins + {{ + {16, 17, 18}, + {19, 20, 21}, + }}, + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/13-cc-potentiometer.md b/docs/examples/01-output/13-cc-potentiometer.md new file mode 100644 index 0000000..7d04a6f --- /dev/null +++ b/docs/examples/01-output/13-cc-potentiometer.md @@ -0,0 +1,30 @@ +# CCPotentiometer + +Analog input mapped to CC value 0-127. + +> Original: `Control-Change-Potentiometer.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCPotentiometer pot { + 26, // ADC pin (GPIO 26 = ADC0) + {MIDI_CC::Channel_Volume, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/14-pb-potentiometer.md b/docs/examples/01-output/14-pb-potentiometer.md new file mode 100644 index 0000000..b6afacc --- /dev/null +++ b/docs/examples/01-output/14-pb-potentiometer.md @@ -0,0 +1,30 @@ +# PBPotentiometer + +Analog input mapped to 14-bit Pitch Bend. + +> Original: `Pitch-Bend-Potentiometer.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBPotentiometer pot { + 26, // ADC pin + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/15-cc-rotary-encoder.md b/docs/examples/01-output/15-cc-rotary-encoder.md new file mode 100644 index 0000000..cc756d1 --- /dev/null +++ b/docs/examples/01-output/15-cc-rotary-encoder.md @@ -0,0 +1,33 @@ +# CCRotaryEncoder + +Relative CC encoder for DAW parameter control. + +> Original: `RotaryEncoder.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCRotaryEncoder enc { + {0, 2}, // encoder pins A and B (constructs AHEncoder) + {16, Channel_1}, // CC address + 1, // speed multiplier + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/16-cc-absolute-encoder.md b/docs/examples/01-output/16-cc-absolute-encoder.md new file mode 100644 index 0000000..04ccfd9 --- /dev/null +++ b/docs/examples/01-output/16-cc-absolute-encoder.md @@ -0,0 +1,32 @@ +# CCAbsoluteEncoder + +Encoder position mapped to absolute CC value. + +> Original: `AbsoluteRotaryEncoder.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCAbsoluteEncoder enc { + {0, 2}, // encoder pins + MIDI_CC::Pan, // CC address + 1, // speed multiplier + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/17-pb-absolute-encoder.md b/docs/examples/01-output/17-pb-absolute-encoder.md new file mode 100644 index 0000000..b6843cc --- /dev/null +++ b/docs/examples/01-output/17-pb-absolute-encoder.md @@ -0,0 +1,30 @@ +# PBAbsoluteEncoder + +Encoder position mapped to 14-bit Pitch Bend. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBAbsoluteEncoder enc { + {0, 2}, // encoder pins + Channel_1, + 127, // large multiplier for PB's 14-bit range + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/18-cc-increment-decrement-buttons.md b/docs/examples/01-output/18-cc-increment-decrement-buttons.md new file mode 100644 index 0000000..68abe3d --- /dev/null +++ b/docs/examples/01-output/18-cc-increment-decrement-buttons.md @@ -0,0 +1,33 @@ +# CCIncrementDecrementButtons + +Two buttons for CC increment/decrement with optional reset. + +> Original: `CCIncrementDecrementButtons.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCIncrementDecrementButtons buttons { + {5, 6}, // increment pin, decrement pin + {16, Channel_1}, // CC address + 1, // multiplier + {0x45, Channel_1}, // reset note (sent when both pressed) +}; + +int main() { + stdio_init_all(); + RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/19-program-changer.md b/docs/examples/01-output/19-program-changer.md new file mode 100644 index 0000000..4cfdca9 --- /dev/null +++ b/docs/examples/01-output/19-program-changer.md @@ -0,0 +1,41 @@ +# ProgramChanger + +Sends different program changes based on selector state. + +> Original: `Program-Changer.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +ProgramChanger<4> programChanger { + {{ + MIDI_PC::Acoustic_Grand_Piano, + MIDI_PC::Rock_Organ, + MIDI_PC::Steel_Drums, + MIDI_PC::Pad_2, + }}, + Channel_1, +}; + +IncrementDecrementSelector<4> selector { + programChanger, + {2, 3}, + Wrap::Wrap, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/20-cc-potentiometers.md b/docs/examples/01-output/20-cc-potentiometers.md new file mode 100644 index 0000000..cf182a7 --- /dev/null +++ b/docs/examples/01-output/20-cc-potentiometers.md @@ -0,0 +1,31 @@ +# Multiple CCPotentiometers + +Several analog inputs mapped to CC on different channels. + +> Original: `Multiple-Control-Change-Potentiometers.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCPotentiometer pots[] { + {26, {MIDI_CC::Channel_Volume, Channel_1}}, + {27, {MIDI_CC::Channel_Volume, Channel_2}}, + {28, {MIDI_CC::Channel_Volume, Channel_3}}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/21-borrowed-cc-rotary-encoder.md b/docs/examples/01-output/21-borrowed-cc-rotary-encoder.md new file mode 100644 index 0000000..af1db94 --- /dev/null +++ b/docs/examples/01-output/21-borrowed-cc-rotary-encoder.md @@ -0,0 +1,32 @@ +# BorrowedCCRotaryEncoder + +Shared encoder reference for CC output, allowing multiple elements to read the same physical encoder. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +AHEncoder encoder {0, 2}; + +BorrowedCCRotaryEncoder enc { + encoder, + {16, Channel_1}, + 1, + 4, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/01-output/_index.md b/docs/examples/01-output/_index.md new file mode 100644 index 0000000..e85be58 --- /dev/null +++ b/docs/examples/01-output/_index.md @@ -0,0 +1,3 @@ +# MIDI Output Elements + +Output elements read physical controls (buttons, potentiometers, encoders) and send MIDI messages. diff --git a/docs/examples/02-input/01-note-led.md b/docs/examples/02-input/01-note-led.md new file mode 100644 index 0000000..69f1c23 --- /dev/null +++ b/docs/examples/02-input/01-note-led.md @@ -0,0 +1,30 @@ +# NoteLED + +LED responds to incoming Note On/Off messages. + +> Original: `1.Note-LED.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteLED led { + 13, // LED pin + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/02-note-range-leds.md b/docs/examples/02-input/02-note-range-leds.md new file mode 100644 index 0000000..57b89a6 --- /dev/null +++ b/docs/examples/02-input/02-note-range-leds.md @@ -0,0 +1,32 @@ +# NoteRangeLEDs + +Multiple LEDs respond to a range of incoming notes. + +> Original: `2.Note-Range-LEDs.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteLED leds[] { + {2, {MIDI_Notes::C[4], Channel_1}}, + {3, {MIDI_Notes::D[4], Channel_1}}, + {4, {MIDI_Notes::E[4], Channel_1}}, + {5, {MIDI_Notes::F[4], Channel_1}}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/03-cc-value.md b/docs/examples/02-input/03-cc-value.md new file mode 100644 index 0000000..754a936 --- /dev/null +++ b/docs/examples/02-input/03-cc-value.md @@ -0,0 +1,29 @@ +# CCValue + +Reads incoming CC messages and stores the value. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCValue ccVal { + {MIDI_CC::Channel_Volume, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/04-pb-value.md b/docs/examples/02-input/04-pb-value.md new file mode 100644 index 0000000..aa7920f --- /dev/null +++ b/docs/examples/02-input/04-pb-value.md @@ -0,0 +1,29 @@ +# PBValue + +Reads incoming Pitch Bend messages (14-bit). + +> Original: `Pitch-Bend-Value.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBValue pbVal {Channel_1}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint16_t val = pbVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/05-note-value.md b/docs/examples/02-input/05-note-value.md new file mode 100644 index 0000000..7048c41 --- /dev/null +++ b/docs/examples/02-input/05-note-value.md @@ -0,0 +1,27 @@ +# NoteValue + +Reads incoming Note On values (8-bit). + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteValue noteVal {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = noteVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/06-kp-value.md b/docs/examples/02-input/06-kp-value.md new file mode 100644 index 0000000..e989d30 --- /dev/null +++ b/docs/examples/02-input/06-kp-value.md @@ -0,0 +1,27 @@ +# KPValue + +Reads incoming Key Pressure (aftertouch) values. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +KPValue kpVal {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = kpVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/07-cc-led.md b/docs/examples/02-input/07-cc-led.md new file mode 100644 index 0000000..1f7658d --- /dev/null +++ b/docs/examples/02-input/07-cc-led.md @@ -0,0 +1,28 @@ +# CCLED + +LED responds to incoming CC messages. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCLED led { + 13, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/08-note-range.md b/docs/examples/02-input/08-note-range.md new file mode 100644 index 0000000..2e231b0 --- /dev/null +++ b/docs/examples/02-input/08-note-range.md @@ -0,0 +1,29 @@ +# NoteRange + +Reads a contiguous range of incoming Note values. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteRange<4> noteRange {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + for (uint8_t i = 0; i < 4; i++) { + uint8_t val = noteRange.getValue(i); + (void)val; + } + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/09-cc-range.md b/docs/examples/02-input/09-cc-range.md new file mode 100644 index 0000000..1fe114f --- /dev/null +++ b/docs/examples/02-input/09-cc-range.md @@ -0,0 +1,29 @@ +# CCRange + +Reads a contiguous range of incoming CC values. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCRange<8> ccRange {{MIDI_CC::General_Purpose_Controller_1, Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + for (uint8_t i = 0; i < 8; i++) { + uint8_t val = ccRange.getValue(i); + (void)val; + } + sleep_ms(1); + } +} +``` diff --git a/docs/examples/02-input/_index.md b/docs/examples/02-input/_index.md new file mode 100644 index 0000000..0a93617 --- /dev/null +++ b/docs/examples/02-input/_index.md @@ -0,0 +1,3 @@ +# MIDI Input Elements + +Input elements receive MIDI messages and drive outputs (LEDs, stored values). diff --git a/docs/examples/03-interfaces/01-ble-midi.md b/docs/examples/03-interfaces/01-ble-midi.md new file mode 100644 index 0000000..b072b68 --- /dev/null +++ b/docs/examples/03-interfaces/01-ble-midi.md @@ -0,0 +1,26 @@ +# BLE MIDI + +Basic Bluetooth Low Energy MIDI interface setup. Replaces `USBMIDI_Interface` from the original library. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; +CCRotaryEncoder enc {{0, 2}, {16, Channel_1}, 1, 4}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/03-interfaces/02-midi-pipes.md b/docs/examples/03-interfaces/02-midi-pipes.md new file mode 100644 index 0000000..02b9c07 --- /dev/null +++ b/docs/examples/03-interfaces/02-midi-pipes.md @@ -0,0 +1,27 @@ +# MIDI Pipes + +Routing between MIDI interfaces using pipe operators. + +> Original: `MIDI_Pipes-Routing.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface ble; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/03-interfaces/_index.md b/docs/examples/03-interfaces/_index.md new file mode 100644 index 0000000..0fad7f4 --- /dev/null +++ b/docs/examples/03-interfaces/_index.md @@ -0,0 +1,3 @@ +# MIDI Interfaces + +Interface setup and routing between MIDI transports. diff --git a/docs/examples/04-banks/01-bank-cc-values.md b/docs/examples/04-banks/01-bank-cc-values.md new file mode 100644 index 0000000..bc521c1 --- /dev/null +++ b/docs/examples/04-banks/01-bank-cc-values.md @@ -0,0 +1,53 @@ +# Bank with CC Values + +Bank switching with bankable input elements. Bank switching changes the CC address listened to. + +> Original: `Bank.ino` (adapted) + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +// 4 banks, 2 tracks per bank +Bank<4> bank(2); + +// Selector: two buttons to increment/decrement the active bank +IncrementDecrementSelector<4> selector { + bank, + {2, 3}, + Wrap::Wrap, +}; + +// Bankable CC value readers — bank switching changes the CC address. +// Bank 1: reads CC 16, CC 17 +// Bank 2: reads CC 18, CC 19 +// Bank 3: reads CC 20, CC 21 +// Bank 4: reads CC 22, CC 23 +Bankable::CCValue<4> ccVal1 { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; +Bankable::CCValue<4> ccVal2 { + {bank, BankType::ChangeAddress}, + {17, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t v1 = ccVal1.getValue(); + uint8_t v2 = ccVal2.getValue(); + (void)v1; + (void)v2; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/02-transposer.md b/docs/examples/04-banks/02-transposer.md new file mode 100644 index 0000000..51be60a --- /dev/null +++ b/docs/examples/04-banks/02-transposer.md @@ -0,0 +1,35 @@ +# Transposer + +Note transposition via increment/decrement buttons. + +> Original: `Transposer.ino` + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Transposer<-12, +12> transposer; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; + +IncrementDecrementSelector<25> selector { + transposer, + {2, 3}, + Wrap::Clamp, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/03-encoder-selector.md b/docs/examples/04-banks/03-encoder-selector.md new file mode 100644 index 0000000..ad81436 --- /dev/null +++ b/docs/examples/04-banks/03-encoder-selector.md @@ -0,0 +1,39 @@ +# EncoderSelector + +Bank selection via rotary encoder. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(2); + +Bankable::CCValue<4> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +EncoderSelector<4> selector { + bank, + {0, 2}, + 4, + Wrap::Wrap, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/04-many-buttons-selector.md b/docs/examples/04-banks/04-many-buttons-selector.md new file mode 100644 index 0000000..b817e65 --- /dev/null +++ b/docs/examples/04-banks/04-many-buttons-selector.md @@ -0,0 +1,37 @@ +# ManyButtonsSelector + +One button per bank for direct bank selection. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(2); + +Bankable::CCValue<4> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +ManyButtonsSelector<4> selector { + bank, + {2, 3, 4, 5}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/05-switch-selector.md b/docs/examples/04-banks/05-switch-selector.md new file mode 100644 index 0000000..9e0aa0d --- /dev/null +++ b/docs/examples/04-banks/05-switch-selector.md @@ -0,0 +1,37 @@ +# SwitchSelector + +Two-state bank selection from a toggle switch. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<2> bank(1); + +Bankable::CCValue<2> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +SwitchSelector selector { + bank, + 5, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/06-program-change-selector.md b/docs/examples/04-banks/06-program-change-selector.md new file mode 100644 index 0000000..97cf5b9 --- /dev/null +++ b/docs/examples/04-banks/06-program-change-selector.md @@ -0,0 +1,37 @@ +# ProgramChangeSelector + +Bank selection triggered by incoming MIDI Program Change messages. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<8> bank(1); + +Bankable::CCValue<8> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +ProgramChangeSelector<8> selector { + bank, + {Channel_1, Cable_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/07-bankable-note-led.md b/docs/examples/04-banks/07-bankable-note-led.md new file mode 100644 index 0000000..c0de759 --- /dev/null +++ b/docs/examples/04-banks/07-bankable-note-led.md @@ -0,0 +1,37 @@ +# Bankable NoteLED + +Bank-switched LED responds to different notes per bank. + +```cpp +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(1); + +IncrementDecrementSelector<4> selector { + bank, + {2, 3}, + Wrap::Wrap, +}; + +Bankable::NoteLED<4> led { + {bank, BankType::ChangeAddress}, + 13, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} +``` diff --git a/docs/examples/04-banks/_index.md b/docs/examples/04-banks/_index.md new file mode 100644 index 0000000..771fa7a --- /dev/null +++ b/docs/examples/04-banks/_index.md @@ -0,0 +1,3 @@ +# Banks and Selectors + +Bank switching allows a single physical control to address multiple MIDI parameters. diff --git a/docs/examples/_index.md b/docs/examples/_index.md new file mode 100644 index 0000000..0ad7f23 --- /dev/null +++ b/docs/examples/_index.md @@ -0,0 +1,3 @@ +# Examples + +Each example is a 1:1 adaptation of the corresponding [Control Surface example](https://tttapa.github.io/Control-Surface/Doxygen/d4/de9/examples.html), rewritten for pico-sdk conventions. All examples are compile-verified. diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..48dd47a --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,87 @@ +# cs-midi Roadmap + +Extraction status of [tttapa/Control-Surface](https://github.com/tttapa/Control-Surface) (GPL-3.0) into cs-midi for pico-sdk + BTstack. + +## Implemented + +### MIDI Output Elements +- [x] `NoteButton` — momentary note on/off +- [x] `NoteButtons` — multiple sequential note buttons +- [x] `NoteButtonLatched` — toggle note on first press, off second +- [x] `NoteButtonLatching` — note on while held, toggles state +- [x] `NoteButtonMatrix` — row/column scanned note grid +- [x] `NoteChordButton` — plays chord on press +- [x] `CCButton` — momentary CC 127/0 +- [x] `CCButtons` — multiple sequential CC buttons +- [x] `CCButtonLatched` — toggle CC +- [x] `CCButtonLatching` — latching CC +- [x] `CCButtonMatrix` — row/column scanned CC grid +- [x] `CCPotentiometer` — analog input to CC 0-127 +- [x] `PBPotentiometer` — analog input to 14-bit Pitch Bend +- [x] `CCRotaryEncoder` — relative CC encoder +- [x] `CCAbsoluteEncoder` — absolute CC encoder +- [x] `PBAbsoluteEncoder` — absolute Pitch Bend encoder +- [x] `CCIncrementDecrementButtons` — inc/dec CC with reset +- [x] `PCButton` — Program Change on press +- [x] `ProgramChanger` — bank-selectable program changes + +### MIDI Input Elements +- [x] `NoteValue` / `CCValue` / `KPValue` — 8-bit value readers +- [x] `PBValue` — 14-bit Pitch Bend reader +- [x] `NoteRange` / `CCRange` / `KPRange` — range readers +- [x] `NoteLED` / `CCLED` / `KPLED` — LED output from MIDI input +- [x] All bankable variants (`Bankable::NoteValue`, etc.) + +### Banks & Selectors +- [x] `Bank` — groups bankable elements, manages bank switching +- [x] `Transposer` — specialized bank for note transposition +- [x] `EncoderSelector` — rotary encoder bank selection +- [x] `IncrementDecrementSelector` — two-button bank selection +- [x] `IncrementSelector` — single-button wrapping selector +- [x] `ManyButtonsSelector` — direct bank selection per button +- [x] `SwitchSelector` — two-state toggle selector +- [x] `ProgramChangeSelector` — MIDI-driven bank selection + +### MIDI Interfaces +- [x] `BluetoothMIDI_Interface` — BLE MIDI via BTstack (pico-native) +- [x] `MIDI_Pipe` / `MIDI_PipeFactory` / `BidirectionalMIDI_PipeFactory` +- [x] `Control_Surface` singleton — declarative begin/loop lifecycle + +### Infrastructure +- [x] `AHEncoder` — pico-native interrupt-driven rotary encoder +- [x] `ExtendedInputOutput` — GPIO abstraction (direct pins) +- [x] MIDI constants (notes, CC numbers, PC programs, chords/intervals) +- [x] Platform shim (`pico_shim.h`) — replaces Arduino runtime + +## Not Yet Implemented + +### Bankable Output Elements +- [ ] `Bankable::NoteButton` / `Bankable::CCButton` / etc. +- [ ] `Bankable::CCPotentiometer` / `Bankable::PBPotentiometer` +- [ ] `Bankable::CCRotaryEncoder` / `Bankable::CCAbsoluteEncoder` +- [ ] `Bankable::NoteChordButton` (with Transposer) +- [ ] `Bankable::NoteButtonMatrix` / `Bankable::CCButtonMatrix` + +*Blocked Phase 11 of the extraction. Required for Bank.ino and Transposer.ino +output-side examples.* + +### Additional MIDI Interfaces +- [ ] USB MIDI Interface (TinyUSB) +- [ ] Serial/Hardware MIDI Interface +- [ ] Debug MIDI Interface (serial monitor output) + +### Display Elements +- [ ] OLED display support +- [ ] VU meter elements +- [ ] NoteLEDBar + +### Hardware Expansion +- [ ] MCP23017 I2C I/O expander +- [ ] MAX7219 LED driver +- [ ] Shift register chains (74HC595, etc.) +- [ ] FastLED / NeoPixel integration + +### Advanced Features +- [ ] MIDI input fine-grained callbacks (per-message-type) +- [ ] SysEx send/receive helpers +- [ ] AppleMIDI (RTP-MIDI over WiFi)