Sunday, May 10, 2026

MPXV7002 as Breath Sensor

Breath sensor made from an MPXV7002 and a silicon tube. The tube has incisions added near the breathing end to allow air to flow through while still building pressure at the sensor end. Enough pressure is still built up within the tube to allow circular breathing if desired. The sensor sends note on / off and continuous control data.

To improve this I might consider a wider tube that is coupled with the sensor or try more or different-sized puncture holes or a 3D printed mouthpiece. However, it still works really well as-is.

Wiring is simple as the sensor outputs an analog voltage and works fine on 3v3 or 5v power supply. The output voltage is rail to rail across the power supply voltage range, and can represent both positive and negative pressure, meaning that the neutral pressure will output at halfway of the voltage supply.

For a Teensy 3.x or 4.x: 3v3 to the 5V pin on the sensor, ground to ground and output of the sensor to Teensy A0 analog input pin.



Here is some code as an example: 


int air_pin = A0;
int air_pressure;
int air_pressure_prev;
int breath_controller = 1;

int threshold = 75;
int play_flag = 0;

int channel = 1;
int pitch = 60;
int velocity = 127;

void setup() {
Serial.begin(57600);
usbMIDI.read();
}

void loop() {
air_pressure = analogRead(air_pin) >> 3;
if(air_pressure != air_pressure_prev) {
air_pressure_prev = air_pressure;
usbMIDI.sendControlChange(breath_controller, air_pressure, channel);
Serial.println(air_pressure);
delay(10);
}

if(air_pressure > threshold && play_flag == 0) {
usbMIDI.sendNoteOn(pitch, velocity, channel);
Serial.println("note on");
play_flag = 1;
}

if(air_pressure < threshold && play_flag == 1) {
usbMIDI.sendNoteOff(pitch, 0, channel);
Serial.println("note off");
play_flag = 0;
}

}


Wednesday, June 25, 2025

Tutorial: How to Vibe Code Max Externals with Claude Code

Sunday, June 22, 2025

Generating a 360 Video from Still Image and 4ch Ambisonics File



Create a video from a still image. Combine the video created in the previous step with 4 channel audio. Inject the correct 360 metadata into the video created in the previous step. Requires ffmpg and spatial-media. 

Download example gradient here: 

https://universityofadelaide.box.com/s/q8g5f31kw5iabtishv4sg93zag2ltgzh 

Download short ambix wav file here: 

https://universityofadelaide.box.com/s/qrrd87dztepn4lxi3uv7m1wyj3zvgkn6 


ffmpeg -loop 1 -i [input image file] -t 8 -vf format=yuv420p -c:v libx264 [output video file 1]

ffmpeg -i [input video file 1] -i [input ambisonics audio file] -c:v copy -c:a pcm_s24le -map 0:v:0 -map 1:a:0 [output video file 2]

python spatialmedia -i -a [output video file 1] [output video file 3]

Monday, June 02, 2025

xNT Hand Implant to Webhook to Home Assistant Event Trigger



 https://www.instagram.com/p/DKZQHQBi4Eq/ 


#include <WiFi.h>
#include <HTTPClient.h>
#include <SPI.h>
#include <MFRC522.h>

// === Wi-Fi credentials ===
const char* ssid = "SSID";
const char* password = "password";

// === Home Assistant Webhook endpoint ===
const char* webhook_url = "http://HA_IP_ADDRESS:8123/api/webhook/rfid_trigger";

// === SPI Pin Assignments for Xiao ===
#define RST_PIN 3
#define SS_PIN 7

MFRC522 mfrc522(SS_PIN, RST_PIN);

// === Setup ===
void setup() {
Serial.begin(115200);
while (!Serial);

Serial.println("Connecting to Wi-Fi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi connected.");

Serial.println("Initializing RFID...");
SPI.begin(8, 9, 10); // SCK, MISO, MOSI
mfrc522.PCD_Init();
Serial.println("Ready to scan tags.");
}

// === Send UID to Home Assistant via Webhook ===
void sendWebhook(String uid) {
if (WiFi.status() != WL_CONNECTED) return;

HTTPClient http;
http.begin(webhook_url);
http.addHeader("Content-Type", "application/json");

String payload = "{\"uid\": \"" + uid + "\"}";
int code = http.POST(payload);
Serial.print("Sent UID: "); Serial.print(uid);
Serial.print(" | HTTP Response: "); Serial.println(code);
http.end();
}

// === Main loop ===
void loop() {
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) return;

String uid = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (mfrc522.uid.uidByte[i] < 0x10) uid += "0";
uid += String(mfrc522.uid.uidByte[i], HEX);
}
uid.toUpperCase();

Serial.println("Scanned UID: " + uid);
sendWebhook(uid);

delay(2000); // debounce
mfrc522.PICC_HaltA();
}

Sunday, June 01, 2025

Teensy Basics: Distance Sensing with VL53L0X Laser Sensor

Overview

The VL53L0X is a ranging sensor that uses time-of-flight of a laser to determine the distance to the next surface correct to the mm with a maximum of 2m. The sensor uses an i2c interface with a default address of 0x29. The xshut pin allows for address control and start up / shut down during setup. 


Hardware Setup

Here are the pinouts for the Teensy 4.1 and the VL53L0X: 



Make the following connections between the Teensy 4.1 and the sensor: 

  • Teensy GND to VL53L0X GND
  • Teensy 3v3 to VL53L0X VIN
  • Teensy pin 0 to VL53L0X XSHUT
  • VL53L0X unconnected
  • Teensy pin 18 to VL53L0X SDA
  • Teensy pin 19 to VL53L0X SCL

No other passive components are required. 





Software setup

This sensor example requires the Pololu vl53l0x library, which is available from the Arduino library manager. 


Example: Reading distance and printing to the serial monitor

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

// XSHUT pin for VL53L0X
const int XSHUT_PIN = 0;

void setup() {
Serial.begin(115200);
Wire.begin(); // SDA = 18, SCL = 19 on Teensy 4.1
delay(100);

// Initialize XSHUT pin
pinMode(XSHUT_PIN, OUTPUT);
digitalWrite(XSHUT_PIN, LOW); // Reset sensor
delay(10);
digitalWrite(XSHUT_PIN, HIGH); // Power up sensor
delay(10);

// Initialize VL53L0X
sensor.setTimeout(500);
if (!sensor.init()) {
Serial.println("Failed to detect VL53L0X.");
while (1);
}

sensor.startContinuous();
Serial.println("VL53L0X started.");
}

void loop() {
uint16_t distance = sensor.readRangeContinuousMillimeters();

Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" mm");

if (sensor.timeoutOccurred()) {
Serial.println("TIMEOUT");
}

delay(20);
}

Saturday, April 26, 2025

Max Gen Filter Cookbook


256 tap manual finite response filter

https://github.com/little-scale/littlescale-max-patches/blob/master/manual_fir_filter.maxpat 


Morphing-type biquad filter

https://github.com/little-scale/littlescale-max-patches/blob/master/biquad_testing.maxpat 

https://github.com/little-scale/littlescale-max-patches/blob/master/biquad-full-basic.gendsp



12 stage biquad lowpass with outputs at 12, 48, 96 and 144 db per octave

https://github.com/little-scale/littlescale-max-patches/blob/master/duodecim-biquad.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/duodecim-biquad.gendsp


50 stage single pole lowpass

https://github.com/little-scale/littlescale-max-patches/blob/master/singlepole-cascading.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/singlepole.gendsp

https://github.com/little-scale/littlescale-max-patches/blob/master/singlepole.maxpat


Basic biquad implementation of lpf, hpf, bpf, notch, all, shelves in one gen~ patch

https://github.com/little-scale/littlescale-max-patches/blob/master/biquad-full-basic.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/biquad-full-basic.gendsp


Moog-style ladder filter with resonance and saturation

https://github.com/little-scale/littlescale-max-patches/blob/master/ladder-filter.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/ladder-filter.gendsp


Harmonic resonant bandpass bank with 16 partials and controls for central partial and gain spread.

https://github.com/little-scale/littlescale-max-patches/blob/master/reson-bpf-harmonic-bank.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/reson-bpf-harmonic-bank.gendsp


Resonant bandpass filter

https://github.com/little-scale/littlescale-max-patches/blob/master/reson-bpf.maxpat

https://github.com/little-scale/littlescale-max-patches/blob/master/reson-bpf.gendsp




Third order (3ff / 3fb) filter with LFO modulation across all co-efficients

https://github.com/little-scale/littlescale-max-patches/blob/master/filter-3ff-3fb.maxpat



Friday, October 04, 2024

Building Supercollider for Raspberry Pi Zero 2

 


Sunday, March 10, 2024

Pyramid Controller

 

My pyramid controller is almost identical to my sphere controller. The difference in shape means that each side feels a little like a preset, and its easier to have an intuition about rotation and orientation compared to a sphere. The code is slightly different as it doesn't adjust brightness; this looks better in my opinion. The code and model files can be found here: https://github.com/little-scale/Music-Sphere-Controller alongside a Max patch that makes it easy to get the data from the pyramid. The board will transmit x y and z data streams for acceleration, gyroscope and magnetometer. The acceleration values determine the colour of the onboard LED. Printing in white or clear PLA makes the colour shine through nicely. 

Wednesday, February 21, 2024

Tuned GPT Guides for Ableton, Max, Sibelius, ProTools and Arduino / Teensy

Teensy Guide: https://chat.openai.com/g/g-yO4mMkzpZ-teensy-guide 

Ableton Guide: https://chat.openai.com/g/g-Kq9jvY4EP-ableton-live-guide

Sibelius Guide: https://chat.openai.com/g/g-qeHztCVqo-sibelius-guide

ProTools Guide: https://chat.openai.com/g/g-Eg0hDUysG-protools-guide 

Max Guide: https://chat.openai.com/g/g-4JogjMsDG-max-guide

Thursday, November 30, 2023

Printable Variable Miniskiff

 


I've added a variable miniskiff part studio to the Eurorack case document: https://cad.onshape.com/documents/1637ca71f6ccbf900471de5e/w/ba5b8495e9753650883d1cb0/e/c3f73f4b0fd00e64b5823644?renderMode=0&uiState=656884e93534192f492a1c3b 

This part studio has variables for many aspects of the case including the width in HP. 46 HP is the widest case that will print on a 25 cm 3 volume printer like the Bambu P1P

Tiptop Buchla Eurorack Case 3D Printed






So the @tiptopaudiofficial #eurorack #modular #buchla series modules are a total of 2HP too long to fit in a standard 104HP case. I designed and printed a 108HP case with space for a uZeus power supply module. The minimal design is the perfect shape for these modules, and due to the large size is printed in six sections. I've also included a 1HP blank to fill the space of the top row. Really happy with how this #3dprinting turned out on a @bambulab_official P1P with the Bambu basic PLA!

https://www.thingiverse.com/thing:6342755


https://cad.onshape.com/documents/1637ca71f6ccbf900471de5e/w/ba5b8495e9753650883d1cb0/e/ee0ea2d55b6411628ab5e8ed?renderMode=0&uiState=656867063534192f4929ef94

Saturday, November 25, 2023

Mediapipe Object Detection Solution to OSC

 


Download here: https://github.com/little-scale/mediapipe-object-osc

Adds basic OSC output for the Mediapipe object detection solution

By default, OSC will be sent to 127.0.0.1 localhost on port 3000 and with address /mediapipe/objects. This can be changed in utils.py

Each OSC message contains: Category name, object detection instance within the frame, normalised x position, normalised y position and certainty

An example Ableton Max for Live device is provided which allows mapping an object class with x and y position to Ableton parameters

Friday, November 24, 2023

ArUco2osc

Send ArUco marker detections as OSC messages

Download here: https://github.com/little-scale/ArUco2osc 

Repo contains 50 4x4 markers



To use:

  • pip install opencv-contrib-python
  • pip install python-osc
  • python aruco2osc.py

Args are:

  • --input: camera to use; default 0
  • --address: OSC message address to use; default /aruco/marker
  • --ip: OSC IP address to use; default 127.0.0.1
  • --port: OSC port to use; default 3001

Each message contains:

  • marker identity
  • size as a normalised ratio
  • angle in degrees
  • x value of midpoint of marker as a normalised value
  • y value of midpoint of marker as a normalised value

To change the marker type used for detection, change DICT_4X4_50 to a different value

Example Max Patch for receiving ArUCo detections: 




Wednesday, November 22, 2023

Running labelimg Under Ventura

Download labelimg to desktop


/usr/bin/python3 -m venv env

source env/bin/activate 

pip install --upgrade pip

pip install PyQt5

cd desktop/labelImg-master

pip3 install pyqt5 lxml

make qt5py3

python3 labelImg.py 

Thursday, November 16, 2023

Mediapipe Facemesh Landmarks Map

 






Mediapipe Holistic Solution to OSC


Taking the legacy Mediapipe holistic solution (face + pose + left hand + right hand) and sending all 543 landmarks via OSC to Max or other places. 

https://github.com/little-scale/mediapipe-holistic-osc 

Monday, November 13, 2023

Mediapipe Hand Solution on Raspberry Pi to OSC to Modular CV / Gate


Setup: 

  1. Set up a Raspberry Pi 4 with a clean install of Raspberry Pi OS: https://www.raspberrypi.com/software/ 
  2. Install Mediapipe as per the instructions here: https://github.com/googlesamples/mediapipe/tree/main/examples/pose_landmarker/raspberry_pi
  3. Install Python OSC on the Raspberry Pi: https://pypi.org/project/python-osc/ 
  4. Add detect_osc_pi.py (https://github.com/little-scale/Tele-o-Module/blob/main/software/dectect_pi_osc.py) to mediapipe/examples/hand_landmarker/rasperry_pi
  5. If using my Tele-o module (https://little-scale.blogspot.com/2023/01/tele-o-wifi-bluetooth-to-cv-gate.html) replace ip in detect_osc_pi.py with the address of the ESP32 in the module. 
  6. If using a different OSC endpoint, replace ip in detect_osc_pi.py with the appropriate address. 
  7. It may be beneficial to change the port variable in detect_osc_pi.py - the default is 3000
  8. Pressing together or releasing the thumb and index finger sends a 1 or 0 on OSC path /gate/0
  9. The distance between the thumb and index finger sends a float 0 - 1 on OSC path /cv/0
  10. The X and Y co-ordinates of the index finger are sent as floats of 0 -1 on OSC paths /cv/1 and /cv/2
  11. These OSC paths can be changed with the variables near the top of detect_osc_pi.py

Wednesday, November 08, 2023

YOLOv7 to OSC

 


YOLOv7 pose to OSC output including support for multiple pose detection: https://github.com/little-scale/yolov72osc/ 

Based on the Yolov7 implementation: https://github.com/WongKinYiu/yolov7

Add /p.py, replace /utils/plots.py and download the yolov7-w6-pose.pt model weights from https://github.com/WongKinYiu/yolov7/releases

Default OSC address is /yolo7/pose, IP is localhost and port is 4500. These can be changed in plots.py

Tuesday, August 15, 2023

Media Pipe Facemesh OSC

 


GitHub: https://github.com/little-scale/facemeshosc 

Tuesday, May 09, 2023

Musical Sphere Controllers





I made some musical sphere controllers. They use the Adafruit Feather Sense BLE nRF5284 board. Axis in six dimensions can be mapped to MIDI outputs via a Max patch. Details including code, patch and 3D files can be found in the github repo here: https://github.com/little-scale/Music-Sphere-Controller