diff --git a/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino b/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino
new file mode 100644
index 0000000..6aa3a8c
--- /dev/null
+++ b/Arduino/LEDstream_CircuitPlayground/LEDstream_CircuitPlayground.ino
@@ -0,0 +1,134 @@
+// This is a pared-down version of the LEDstream sketch specifically
+// for Circuit Playground. It is NOT a generic solution to NeoPixel
+// support with Adalight! The NeoPixel library disables interrupts
+// while issuing data...but Serial transfers depend on interrupts.
+// This code works (or appears to work, it hasn't been extensively
+// battle-tested) only because of the finite number of pixels (10)
+// on the Circuit Playground board. With 10 NeoPixels, interrupts are
+// off for about 300 microseconds...but if the incoming data rate is
+// sufficiently limited (<= 60 FPS or so with the given number of
+// pixels), things seem OK, no data is missed. Balancing act!
+
+// --------------------------------------------------------------------
+// This file is part of Adalight.
+
+// Adalight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of
+// the License, or (at your option) any later version.
+
+// Adalight is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with Adalight. If not, see
+// .
+// --------------------------------------------------------------------
+
+#include "Adafruit_CircuitPlayground.h"
+
+static const uint8_t magic[] = { 'A','d','a' };
+#define MAGICSIZE sizeof(magic)
+#define HEADERSIZE (MAGICSIZE + 3)
+static uint8_t
+ buffer[HEADERSIZE], // Serial input buffer
+ bytesBuffered = 0; // Amount of data in buffer
+
+static const unsigned long serialTimeout = 15000; // 15 seconds
+static unsigned long lastByteTime;
+
+void setup() {
+ CircuitPlayground.begin();
+ CircuitPlayground.setBrightness(255); // LEDs full blast!
+ CircuitPlayground.strip.clear();
+ CircuitPlayground.strip.show();
+
+ Serial.begin(38400);
+
+ lastByteTime = millis(); // Initialize timers
+}
+
+// Function is called when no pending serial data is available.
+static boolean timeout(
+ unsigned long t, // Current time, milliseconds
+ int nLEDs) { // Number of LEDs
+
+ // If no data received for an extended time, turn off all LEDs.
+ if((t - lastByteTime) > serialTimeout) {
+ CircuitPlayground.strip.clear();
+ CircuitPlayground.strip.show();
+ lastByteTime = t; // Reset counter
+ bytesBuffered = 0; // Clear serial buffer
+ return true;
+ }
+
+ return false; // No timeout
+}
+
+void loop() {
+ uint8_t i, hi, lo, byteNum;
+ int c;
+ long nLEDs, pixelNum;
+ unsigned long t;
+
+ // HEADER-SEEKING BLOCK: locate 'magic word' at start of frame.
+
+ // If any data in serial buffer, shift it down to starting position.
+ for(i=0; i= 0) { // Data received?
+ buffer[bytesBuffered++] = c; // Store in buffer
+ lastByteTime = t; // Reset timeout counter
+ } else { // No data, check for timeout...
+ if(timeout(t, 10000) == true) return; // Start over
+ }
+ }
+
+ // Have a header's worth of data. Check for 'magic word' match.
+ for(i=0; i 0)
+ nLEDs = 256L * (long)hi + (long)lo + 1L;
+ bytesBuffered = 0; // Clear serial buffer
+ byteNum = 0;
+
+ // DATA-FORWARDING BLOCK: move bytes from serial input to NeoPixels.
+
+ for(pixelNum = 0; pixelNum < nLEDs; ) { // While more LED data is expected...
+ t = millis();
+ if((c = Serial.read()) >= 0) { // Successful read?
+ lastByteTime = t; // Reset timeout counters
+ buffer[byteNum++] = c; // Store in data buffer
+ if(byteNum == 3) { // Have a full LED's worth?
+ CircuitPlayground.strip.setPixelColor(pixelNum++,
+ buffer[0], buffer[1], buffer[2]);
+ byteNum = 0;
+ }
+ } else { // No data, check for timeout...
+ if(timeout(t, nLEDs) == true) return; // Start over
+ }
+ }
+
+ CircuitPlayground.strip.show();
+}
+
diff --git a/Processing/Adalight_CircuitPlayground/Adalight_CircuitPlayground.pde b/Processing/Adalight_CircuitPlayground/Adalight_CircuitPlayground.pde
new file mode 100644
index 0000000..2ba4c93
--- /dev/null
+++ b/Processing/Adalight_CircuitPlayground/Adalight_CircuitPlayground.pde
@@ -0,0 +1,300 @@
+// IMPORTANT: change 'serialPortIndex' to make this work on your system.
+
+// This is a slightly pared-down version of Adalight specifically for
+// Circuit Playground, configured for a single screen and 10 LEDs.
+
+// "Adalight" is a do-it-yourself facsimile of the Philips Ambilight concept
+// for desktop computers and home theater PCs. This is the host PC-side code
+// written in Processing, intended for use with a USB-connected Circuit
+// Playground microcontroller running the accompanying LED streaming code.
+// Screen capture adapted from code by Cedrik Kiefer (processing.org forum)
+
+// --------------------------------------------------------------------
+// This file is part of Adalight.
+
+// Adalight is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of
+// the License, or (at your option) any later version.
+
+// Adalight is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with Adalight. If not, see
+// .
+// --------------------------------------------------------------------
+
+import java.awt.*;
+import java.awt.image.*;
+import processing.serial.*;
+
+// CONFIGURABLE PROGRAM CONSTANTS --------------------------------------------
+
+// This selects from the list of serial devices connected to the system.
+// Use print(Serial.list()); to get a list of ports. Then, counting from 0,
+// set this value to the index corresponding to the Circuit Playground port:
+
+static final byte serialPortIndex = 2;
+
+// For multi-screen systems, set this to the index (counting from 0) of the
+// display which will have ambient lighting:
+
+static final byte screenNumber = 0;
+
+// Minimum LED brightness; some users prefer a small amount of backlighting
+// at all times, regardless of screen content. Higher values are brighter,
+// or set to 0 to disable this feature.
+
+static final short minBrightness = 100;
+
+// LED transition speed; it's sometimes distracting if LEDs instantaneously
+// track screen contents (such as during bright flashing sequences), so this
+// feature enables a gradual fade to each new LED state. Higher numbers yield
+// slower transitions (max of 255), or set to 0 to disable this feature
+// (immediate transition of all LEDs).
+
+static final short fade = 60;
+
+// Depending on many factors, it may be faster either to capture full
+// screens and process only the pixels needed, or to capture multiple
+// smaller sub-blocks bounding each region to be processed. Try both,
+// look at the reported frame rates in the Processing output console,
+// and run with whichever works best for you.
+
+static final boolean useFullScreenCaps = true;
+
+// PER-LED INFORMATION -------------------------------------------------------
+
+// The Circuit Playground version of Adalight operates on a fixed 5x5 grid
+// encompassing the full display. 10 elements from this grid correspond to
+// the 10 NeoPixels on the Circuit Playground board. The following array
+// contains the 2D coordinates of each NeoPixel within that 5x5 grid (0,0 is
+// top left); board assumed facing away from display, with USB at bottom:
+// .4.5.
+// 3...6
+// 2...7
+// 1...8
+// .0.9.
+
+static final int leds[][] = new int[][] {
+ {1,4}, {0,3}, {0,2}, {0,1}, {1,0},
+ {3,0}, {4,1}, {4,2}, {4,3}, {3,4}
+};
+
+// GLOBAL VARIABLES ---- You probably won't need to modify any of this -------
+
+byte serialData[] = new byte[6 + leds.length * 3],
+ gamma[][] = new byte[256][3];
+short[][] ledColor = new short[leds.length][3],
+ prevColor = new short[leds.length][3];
+Robot bot;
+Rectangle dispBounds, ledBounds[];
+int pixelOffset[][] = new int[leds.length][256],
+ screenData[];
+PImage preview;
+Serial port;
+
+// INITIALIZATION ------------------------------------------------------------
+
+void setup() {
+ GraphicsEnvironment ge;
+ GraphicsConfiguration[] gc;
+ GraphicsDevice[] gd;
+ int i, row, col;
+ int[] x = new int[16], y = new int[16];
+ float f, range, step, start;
+
+ this.registerMethod("dispose", this);
+ print(Serial.list()); // Show list of serial devices/ports
+ // Open serial port. Change serialPortIndex in the globals to
+ // select a different port:
+ port = new Serial(this, Serial.list()[serialPortIndex], 38400);
+
+ // Initialize screen capture code for the display's dimensions.
+ if(useFullScreenCaps == false) ledBounds = new Rectangle[leds.length];
+ ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ gd = ge.getScreenDevices();
+
+ try {
+ bot = new Robot(gd[screenNumber]);
+ }
+ catch(AWTException e) {
+ System.out.println("new Robot() failed");
+ exit();
+ }
+ gc = gd[screenNumber].getConfigurations();
+ dispBounds = gc[0].getBounds();
+ dispBounds.x = dispBounds.y = 0;
+ preview = createImage(5, 5, RGB);
+ preview.loadPixels();
+
+ // Precompute locations of every pixel to read when downsampling.
+ // Saves a bunch of math on each frame, at the expense of a chunk
+ // of RAM. Number of samples is now fixed at 256; this allows for
+ // some crazy optimizations in the downsampling code.
+ for(i=0; i> 8); // LED count high byte
+ serialData[4] = (byte)((leds.length - 1) & 0xff); // LED count low byte
+ serialData[5] = (byte)(serialData[3] ^ serialData[4] ^ 0x55); // Checksum
+
+ // Pre-compute gamma correction table for LED brightness levels:
+ for(i=0; i<256; i++) {
+ f = pow((float)i / 255.0, 2.8);
+ gamma[i][0] = (byte)(f * 255.0 + 0.5);
+ gamma[i][1] = (byte)(f * 240.0 + 0.5);
+ gamma[i][2] = (byte)(f * 220.0 + 0.5);
+ }
+}
+
+// PER_FRAME PROCESSING ------------------------------------------------------
+
+void draw () {
+ BufferedImage img;
+ int i, j, o, c, weight, rb, g, sum, deficit, s2;
+ int[] pxls, offs;
+
+ if(useFullScreenCaps == true ) {
+ img = bot.createScreenCapture(dispBounds);
+ // Get location of source pixel data
+ screenData =
+ ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
+ }
+
+ weight = 257 - fade; // 'Weighting factor' for new frame vs. old
+ j = 6; // Serial led data follows header / magic word
+
+ // This computes a single pixel value filtered down from a rectangular
+ // section of the screen. While it would seem tempting to use the native
+ // image scaling in Processing/Java, in practice this didn't look very
+ // good -- either too pixelated or too blurry, no happy medium. So
+ // instead, a "manual" downsampling is done here. In the interest of
+ // speed, it doesn't actually sample every pixel within a block, just
+ // a selection of 256 pixels spaced within the block...the results still
+ // look reasonably smooth and are handled quickly enough for video.
+
+ for(i=0; i> 24) & 0xff) * weight +
+ prevColor[i][0] * fade) >> 8);
+ ledColor[i][1] = (short)(((( g >> 16) & 0xff) * weight +
+ prevColor[i][1] * fade) >> 8);
+ ledColor[i][2] = (short)((((rb >> 8) & 0xff) * weight +
+ prevColor[i][2] * fade) >> 8);
+ // Boost pixels that fall below the minimum brightness
+ sum = ledColor[i][0] + ledColor[i][1] + ledColor[i][2];
+ if(sum < minBrightness) {
+ if(sum == 0) { // To avoid divide-by-zero
+ deficit = minBrightness / 3; // Spread equally to R,G,B
+ ledColor[i][0] += deficit;
+ ledColor[i][1] += deficit;
+ ledColor[i][2] += deficit;
+ } else {
+ deficit = minBrightness - sum;
+ s2 = sum * 2;
+ // Spread the "brightness deficit" back into R,G,B in proportion to
+ // their individual contribition to that deficit. Rather than simply
+ // boosting all pixels at the low end, this allows deep (but saturated)
+ // colors to stay saturated...they don't "pink out."
+ ledColor[i][0] += deficit * (sum - ledColor[i][0]) / s2;
+ ledColor[i][1] += deficit * (sum - ledColor[i][1]) / s2;
+ ledColor[i][2] += deficit * (sum - ledColor[i][2]) / s2;
+ }
+ }
+
+ // Apply gamma curve and place in serial output buffer
+ serialData[j++] = gamma[ledColor[i][0]][0];
+ serialData[j++] = gamma[ledColor[i][1]][1];
+ serialData[j++] = gamma[ledColor[i][2]][2];
+ // Update pixels in preview image
+ preview.pixels[leds[i][1] * 5 + leds[i][0]] = 0xFF000000 |
+ (ledColor[i][0] << 16) | (ledColor[i][1] << 8) | ledColor[i][2];
+ }
+
+ if(port != null) port.write(serialData); // Issue data to Arduino
+
+ // Show live preview image
+ preview.updatePixels();
+ scale(40);
+ image(preview, 0, 0);
+
+ println(frameRate); // How are we doing?
+
+ // Copy LED color data to prior frame array for next pass
+ arraycopy(ledColor, 0, prevColor, 0, ledColor.length);
+}
+
+// CLEANUP -------------------------------------------------------------------
+
+// The DisposeHandler is called on program exit (but before the Serial library
+// is shutdown), in order to turn off the LEDs (reportedly more reliable than
+// stop()). Seems to work for the window close box and escape key exit, but
+// not the 'Quit' menu option. Thanks to phi.lho in the Processing forums.
+
+void dispose() {
+ // Fill serialData (after header) with 0's, and issue to Arduino...
+ java.util.Arrays.fill(serialData, 6, serialData.length, (byte)0);
+ if(port != null) port.write(serialData);
+}
\ No newline at end of file