Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions releases/00_Simple_MIDI/README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
# Simple MIDI
# Simple MIDI (v0.7)

Simple MIDI turns the Music Thing Modular Workshop Computer into a USB MIDI
interface. It sends controls and CV from the Workshop System to a computer, and
turns incoming MIDI notes, gates, and continuous-controller messages into CV and
turns incoming MIDI notes, gates, pitch-bend and continuous-controller messages into CV and
gate signals.

It is also the card used to calibrate the Workshop Computer's two precision CV
outputs. Other cards, including Turing Machine and Reverb+, can use the saved
outputs and audio inputs. Other cards, including Turing Machine and Reverb+, can use the saved
calibration data so that their pitch outputs play in tune.

Simple MIDI was written by Tom Whitwell in Herne Hill, London, between October
2024 and October 2025.
2024 and October 2025 (versions up to 0.6.6), and revised by Chris Johnson in Derbyshire between March and August 2026 (version 0.7.0-)


## What it does

Simple MIDI receives two channels of MIDI from a connected computer:
Simple MIDI receives two channels of MIDI from a connected MIDI device:

- Note pitch
- Note on/off gates
- Continuous Controller 42
- Pitch bend

It sends eight controls from the Workshop System back to the computer:
It sends eight controls from the Workshop System back to the MIDI device:

- Main, X, and Y knobs
- The Z switch
- Both Audio/CV inputs
- Both precision CV inputs

The Workshop System appears on the connected computer as **Workshop System
MIDI** or **Music Thing Workshop System MIDI**.
Simple MIDI can act as a MIDI device (for connection to a computer) or as a MIDI host (for connection to MIDI controllers).
The Workshop System appears on the connected computer as **MTMComputer MIDI** or **Music Thing MTMComputer MIDI**.

[Watch the 90-second Simple MIDI introduction on
Instagram](https://www.instagram.com/reel/DBjZivNN67D/).
Expand All @@ -42,7 +44,7 @@ Instagram](https://www.instagram.com/reel/DBjZivNN67D/).
3. Insert the Simple MIDI card with its gold connector facing down.
4. Press the small Reset/Load button beside the Program Card slot.
5. The LEDs should blink briefly and then stop.
6. Select **Workshop System MIDI** or **Music Thing Workshop System MIDI** in
6. Select **MTMComputer MIDI** or **Music Thing MTMComputer MIDI** in
your DAW or MIDI software.

If the LEDs continue blinking, the USB connection has not been established:
Expand Down
71 changes: 71 additions & 0 deletions releases/00_Simple_MIDI/firmware/AnalogueToMIDI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#ifndef ANALOGUE_TO_MIDI_H
#define ANALOGUE_TO_MIDI_H

// Class that converts a signal in the range min_ to max_ into 7-bit values 0-127
// No filtering, but uses hysteresis to avoid jitter

class AnalogueToMIDI
{
public:
AnalogueToMIDI(int32_t minval_, int32_t maxval_)
{
minval = minval_;
maxval = maxval_;
currentMIDIValue = 0;
previousMIDIValue = 0;
}

void operator()(int32_t in)
{
// Rescale input from 0 to 65535
if (maxval == minval)
{
in = maxval;
}
else
{
in = ((in - minval) << 16) / (maxval - minval);
}

if (in < 0)
{
in = 0;
}
if (in > 65535)
{
in = 65535;
}

// Naive mapping of in (0-65535) to MIDI (0-127) is (in >> 9)
// 0-511 -> 0
// 512-1023 -> 1
// 1024-1535 -> 2 etc.
// Extend these 'windows' by half a window (256) in either direction,
// for hysteresis, and update MIDI output value if outside this window.
int32_t windowMax = ((currentMIDIValue + 1) << 9) + 255;
int32_t windowMin = (currentMIDIValue << 9) - 256;

if (in > windowMax || in < windowMin)
{
currentMIDIValue = in >> 9;
}
}
int8_t GetMIDIValueIfNew()
{
if (currentMIDIValue != previousMIDIValue)
{
previousMIDIValue = currentMIDIValue;
return currentMIDIValue;
}
else
{
return -1;
}
}
private:
int32_t minval, maxval;
volatile int8_t currentMIDIValue;
int8_t previousMIDIValue;
};

#endif
55 changes: 55 additions & 0 deletions releases/00_Simple_MIDI/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
cmake_minimum_required (VERSION 3.13)
include(pico_sdk_import.cmake)
project(simple_midi_2 C CXX ASM)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()

option(OPTIMIZE_SIZE "Optimize for size (-Os) instead of default -O2" OFF)

macro (add_example _name)
add_executable(${ARGV})
if (TARGET ${_name})

# Add warnings, in particular about float/double conversion, as it's very easy to end up
# with slower double-precision calculations when we only mean to use single-precision float.
target_compile_options(${_name} PRIVATE -Wdouble-promotion -Wfloat-conversion -Wall -Wextra -mtune=cortex-m0plus)
if (OPTIMIZE_SIZE)
target_compile_options(${_name} PRIVATE -Os)
endif()
target_link_options(${_name} PRIVATE -Wl,--print-memory-usage)

# Give oscillator more time to start - some boards won't run if this isn't included
target_compile_definitions(${_name} PRIVATE PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)

target_include_directories(${_name} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(${_name} pico_unique_id pico_stdlib hardware_dma hardware_interp hardware_i2c hardware_pwm hardware_adc hardware_spi)
pico_add_extra_outputs(${_name})
target_sources(${_name} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/main.cpp)


pico_set_binary_type(${_name} copy_to_ram)

pico_enable_stdio_usb(${_name} 0)
endif()
endmacro()



add_example(simple_midi_2)

target_link_libraries(simple_midi_2 pico_multicore hardware_sync tinyusb_device tinyusb_host tinyusb_board)
target_sources(simple_midi_2 PUBLIC
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/usb_midi_host.c
${CMAKE_CURRENT_LIST_DIR}/usb_midi_host_app_driver.c)

# Calibration passthrough test: AudioIn millivolts -> CVOut millivolts
add_executable(test_passthrough ${CMAKE_CURRENT_LIST_DIR}/test_passthrough.cpp)
target_compile_options(test_passthrough PRIVATE -Wdouble-promotion -Wfloat-conversion -Wall -Wextra -mtune=cortex-m0plus)
target_compile_definitions(test_passthrough PRIVATE PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
target_link_options(test_passthrough PRIVATE -Wl,--print-memory-usage)
target_include_directories(test_passthrough PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(test_passthrough pico_unique_id pico_stdlib pico_multicore hardware_sync hardware_dma hardware_interp hardware_i2c hardware_pwm hardware_adc hardware_spi)
pico_add_extra_outputs(test_passthrough)
pico_set_binary_type(test_passthrough copy_to_ram)
pico_enable_stdio_usb(test_passthrough 0)
Loading
Loading