Wednesday, November 4, 2026

Nov 3rd Class- Experimenting with Neopixels; MIDI Prototyping

Above: Kerem makes calculations...

 The planned projects seemed to have coalesced into two projects:



Project 1(Stanley-Kexin-Rohan) is a clock wrapped in Neopixels, whose display can be controlled remotely using an Internet of Things app.

Various Neopixels were experimented with. The team has decided to purchase a clock, as the main goal is to control LED lights around the periphery via the Internet.

They were advised that there are two types of neon rope lights- one type uses its own 24V controller, while another type uses programmable LEDs and can be interfaced with a microcontroller.

These include:

* Single-Color Neon Rope Lights: Emit one fixed color (such as amber, blue, red, or green) along the entire run for clean, classic outlines. [1, 2]

* White & Tunable White Neon Rope Lights: Offer static white (warm, cool, or daylight) or adjustable color temperatures (CCT) ranging from warm amber tones to crisp daylight white. [1, 2, 3]

* RGB Neon Rope Lights: Combine Red, Green, and Blue LEDs to produce a wide spectrum of solid colors via a remote or controller. [1, 2]

* RGBIC / Addressable Neon Rope Lights: Feature integrated IC (Independent Control) chips that allow multiple dynamic colors and multi-segment gradients to display simultaneously on a single strip (popular in brands like Govee and Lumary). [1, 2, 3]

The RGBIC / Addressable Neon Rope Lights (including Addressable RGBW variants) can be interfaced to a microcontroller and programmed using Adafruit's NeoPixel software library.

To ensure compatibility, look for lights that use standard 3-wire or 4-wire digital protocols. The most common compatible chipsets inside these neon ropes include:

* WS2812B / WS2811 (Highly compatible, 3-wire: V+, Data, GND)

* SK6812 (Common for RGBW addressable variants, 3-wire)

* WS2813 / WS2815 (Backup data line versions, 4-wire)

They decided to use the RGB type that can be interfaced to a microcontroller.

The plan is to control the lights remotely via a dashboard on the Arduino IOT Cloud:

Controlling NeoPixels remotely via the Arduino IoT Cloud requires an IoT-enabled board (such as a Xiao  ESP32 -C6 Arduino Nano 33 IoT ), a cloud-linked variable of type Colored Light, and a custom dashboard widget. [1, 2]
Hardware and Wiring
  • Microcontroller: Use a Wi-Fi-enabled board compatible with Arduino Cloud.
  • Power Supply: Connect an external 5V power supply to the NeoPixels (do not power many NeoPixels directly from the board's 5V pin).
  • Common Ground: Connect the ground of the external power supply to the ground of your Arduino board.
  • Data Pin: Wire the NeoPixel data-in line to a digital output pin on the Arduino (e.g., pin 2 or 6). [1, 2, 3, 4]
Setting Up Arduino IoT Cloud
  1. Create a Thing: Go to the Arduino Cloud portal and create a new Thing.
  2. Add a Variable: Create a new variable named neopixel with the type set to Colored Light and permissions set to Read & Write.
  3. Build a Dashboard: Navigate to the Dashboards section, create a new dashboard, and add a widget linked to your neopixel variable (such as a color picker or light controller). [1, 2]
Arduino Sketch Logic
  • Include the Adafruit_NeoPixel library and the auto-generated Arduino IoT Cloud header files.
  • Write a callback function in your sketch (triggered whenever the neopixel cloud variable changes) that reads the red, green, blue, and brightness values and updates the LED strip using .setPixelColor() and .show().
  • Run ArduinoCloud.begin() inside setup() and ArduinoCloud.update() inside loop(). [1, 2, 3, 4]
If you want, tell me:
  • Which Arduino board you are using (e.g., Nano 33 IoT, UNO R4 WiFi, ESP32):

    Xiao ESP C3 Super Mini- has built-in Wifi, fits easily into a standard breadboard
  • What type of NeoPixel setup you have (strip, ring, or matrix): Strip, approximately 1 meter in length, wrapped around the clock

------------------------------------------------------------

Project 2 (Kimberly-Lydia-Ashley-Zeno) is an electronic optical music player, that will play notes encoded as holes in a strip of paper. Students tested an non-electronic music play, experimented with sensors and lights, and played notes using an Arduino Mega and a Sparkfun Musical Instrument Shield. It was decided to encode the music as holes in a paper strip, with a line of laser diodes shining through the holes to trigger the notes, as it was more reliable than reflectance sensors, and definitely looks cooler.

 Zeno soldered header pins onto the Sparkfun Musical Instrument Shield, connected it to an Arduino Mega, and got it to play some notes.


  IR Transmitter and receiver:
  


A good time was had by all, as well as a lot of Halloween candy.



Building a photo-optical music box is a fantastic project that blends mechanical tracking with real-time polyphonic MIDI generation.
By utilizing the Arduino Mega, you gain access to an abundance of analog inputs to build a wide polyphonic register (e.g., 8 to 16 notes). The SparkFun Music Instrument Shield (built on the VS1053 chip) handles the audio processing, serving as a dedicated synthesizer that turns raw serial commands from your Arduino into highly accurate instrument sounds (like piano, organ, or brass). [1, 2, 3, 4]

🎹 Core System Architecture
  1. The Optical Reading Gate: You will use an array of optical sensors (such as TCRT5000 IR reflective sensors or Cadmium-Sulfide photoresistors) aligned in a straight line. Each sensor corresponds to a specific musical note. [1, 2]
  2. The Music Roll: A sheet of paper, cardboard, or a 3D-printed wheel with dark marks or holes passes over the gate. When a hole or a mark passes over a sensor, the sensor triggers an analog or digital change. [1, 2]
  3. The Microcontroller: The Arduino Mega reads all sensors simultaneously, flags which notes have shifted states, and sends real-time MIDI instructions down a serial channel.
  4. The Synthesizer Shield: The SparkFun board listens to the serial data at a unique MIDI baud rate (31,250 bps) and outputs polyphonic audio via its 3.5mm headphone jack. [1, 2]

🔌 Wiring Blueprint
Because the SparkFun Musical Instrument Shield is designed in an Arduino Uno form factor, you must explicitly map the serial and reset pins if you are stacking it or wiring it alongside an Arduino Mega. By default, the shield communicates via a SoftwareSerial TX pin assigned to Digital Pin 3, and utilizes Digital Pin 4 for hardware reset. 


     Proof of concept test:



Optical Sensors Wiring:
  • Connect your optical sensor outputs directly to the Mega’s analog array (A0 to A15 depending on how many notes you want).
  • Wire each sensor with appropriate pull-up or pull-down resistors (typically 10kΩ) to guarantee clean, threshold-driven triggers. [1, 2]
Arduino test code that plays a scale on the Sparkfun Musical Instrument Shield:



// On an Arduino Mega, hardware serial can be used, but keeping SoftwareSerial on pins 2 & 3
// maintains direct drop-in pin compatibility with the SparkFun Musical Instrument Shield.
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX = Pin 2, TX = Pin 3
const byte resetMIDI = 4; // Tied to VS1053 Reset line
const byte ledPin = 13; // MIDI traffic indicator

// Pin assignments for the 8 active-low IR sensors (adjust pin numbers to match your wiring)
const byte sensorPins[8] = {22, 23, 24, 25, 26, 27, 28, 29};

// G Major Scale starting at G3 (MIDI note numbers):
// G3 (55), A3 (57), B3 (59), C4 (60), D4 (62), E4 (64), F#4 (66), G4 (67)
const byte scaleNotes[8] = {55, 57, 59, 60, 62, 64, 66, 67};

// Track current and previous trigger states
bool notePlaying[8] = {false, false, false, false, false, false, false, false};

void setup() {
Serial.begin(57600);
pinMode(ledPin, OUTPUT);

// Configure sensor pins with internal pull-ups (ensures HIGH when unlit/blocked)
for (byte i = 0; i < 8; i++) {
pinMode(sensorPins[i], INPUT_PULLUP);
}

// MIDI communication setup at 31250 baud
mySerial.begin(31250);

// Reset the VS1053 chip
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);

// Set default bank: GM1
talkMIDI(0xB0, 0x00, 0x00);
// Set channel 0 volume to max (127)
talkMIDI(0xB0, 0x07, 127);
// Instrument selection: 19 = Church Organ
talkMIDI(0xC0, 19, 0);

Serial.println("Paper tape IR reader ready.");
}

void loop() {
for (byte i = 0; i < 8; i++) {
// Sensor output is active-low: LOW indicates light detected through hole
bool isTriggered = (digitalRead(sensorPins[i]) == LOW);

// Hole detected: start note if not already sounding
if (isTriggered && !notePlaying[i]) {
noteOn(0, scaleNotes[i], 90);
notePlaying[i] = true;
}
// Hole passed / blocked: end note
else if (!isTriggered && notePlaying[i]) {
noteOff(0, scaleNotes[i], 60);
notePlaying[i] = false;
}
}

// Small debounce / scan interval
delay(5);
}

void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI((0x90 | (channel & 0x0F)), note, attack_velocity);
}

void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI((0x80 | (channel & 0x0F)), note, release_velocity);
}

void talkMIDI(byte cmd, byte data1, byte data2) {
digitalWrite(ledPin, HIGH);
mySerial.write(cmd);
mySerial.write(data1);

if ((cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) >= 0xE0) {
mySerial.write(data2);
}
digitalWrite(ledPin, LOW);
}

/*------------------------------------------------------*/

Alternative code from Gemini:
// Photo-Optical Music Box Controller
// Built for Arduino Mega + SparkFun Musical Instrument Shield (VS1053)

#define VS1053_RESET 4 // Shield reset pin
#define NUM_NOTES 8 // Expandable up to 16 notes on the Mega

// Map your optical sensors (A0-A7) to specific MIDI note numbers (C Major Scale shown)
const int sensorPins[NUM_NOTES] = {A0, A1, A2, A3, A4, A5, A6, A7};
const int midiNotes[NUM_NOTES] = {60, 62, 64, 65, 67, 69, 71, 72}; // C4 to C5

// Calibration parameters
const int threshold = 400; // Adjust based on your paper/ambient light environment
bool noteActive[NUM_NOTES] = {false};

void setup() {
// Initialize hardware serial for the VS1053 MIDI Shield at standard MIDI baud rate
Serial1.begin(31250);
// Initialize and cycle the Reset pin on the SparkFun Shield
pinMode(VS1053_RESET, OUTPUT);
digitalWrite(VS1053_RESET, LOW);
delay(10);
digitalWrite(VS1053_RESET, HIGH);
delay(10);

// Configure MIDI Instrument Bank & Voice
setBank(0x00); // Default General MIDI Bank
setInstrument(0); // Instrument #0: Acoustic Grand Piano (Change as desired)
}

void loop() {
for (int i = 0; i < NUM_NOTES; i++) {
int sensorValue = analogRead(sensorPins[i]);
// Check if a note should be triggered (Sensor reads dark space or hole)
if (sensorValue < threshold && !noteActive[i]) {
midiNoteOn(0, midiNotes[i], 90); // Channel 0, Note, Velocity 90
noteActive[i] = true;
}
// Check if the note has ended
else if (sensorValue >= threshold && noteActive[i]) {
midiNoteOff(0, midiNotes[i], 0); // Channel 0, Note, Velocity 0
noteActive[i] = false;
}
}
delay(10); // Polling stability buffer
}

// Send a MIDI Note On Command
void midiNoteOn(uint8_t chan, uint8_t n, uint8_t vel) {
Serial1.write(0x90 | (chan & 0x0F));
Serial1.write(n & 0x7F);
Serial1.write(vel & 0x7F);
}

// Send a MIDI Note Off Command
void midiNoteOff(uint8_t chan, uint8_t n, uint8_t vel) {
Serial1.write(0x80 | (chan & 0x0F));
Serial1.write(n & 0x7F);
Serial1.write(vel & 0x7F);
}

// Set the Instrument Voice
void setInstrument(uint8_t bank) {
Serial1.write(0xC0);
Serial1.write(bank);
}

// Set the Tone Bank
void setBank(uint8_t bank) {
Serial1.write(0xB0);
Serial1.write(0x00);
Serial1.write(bank);
}
Use code with caution

/*-------------------------------------------------------------*/

Paper Feed Motor Test:


No comments:

Post a Comment

Nov 3rd Class- Experimenting with Neopixels; MIDI Prototyping

Above: Kerem makes calculations...  The planned projects seemed to have coalesced into two projects: Project 1(Stanley-Kexin-Rohan) is a clo...