Files
WS-1.0-Firmwares/byte/byte.ino
2025-10-04 23:19:54 +03:00

241 lines
6.6 KiB
C++

// Copyright 2024 Sean Luke
// (sean@cs.gmu.edu)
//
// Released under the Apache 2.0 License
/// BYTE
///
/// Byte is a bytebeat synthesizer similar to ALGODRONE or ByteBeat-Xfade. You can provide
/// up to 16 bytebeat expressions (defined as BYTEBEAT_1 through BYTEBEAT_16 below), and
/// then select and play them. Feel free to change them! But they must be valid C/C++
/// expressions or they won't compile. You can change the pitch and tuning, as well as the
/// volume. Additionally you can reset the bytebeat algorithm at any time by sending a
/// trigger or gate to DIGITAL OUT.
///
/// BUILDING BYTEBEATS
/// A bytebeat is any C expression using the 32-bit variable 't'. It's called 16384 times a second
/// and the result, mod 255, is output as an audio sample.
///
/// Byte has a special feature: a special variable called x which ranges from 0 to 255. It's
/// controlled by CV coming in to IN 3, and is by default 0. You could stick x in your expressions
/// to control them in real-time via CV.
///
/// Byte is fragile: if in your expression you modify Byte's own variables (like triggered or pitchCV
/// or even t!) you can seriously break Byte. So don't do that.
///
///
/// TUNING
///
/// You can't really tune BYTE: to do so would require changing the sampling rate, and Mozzi doesn't
/// make it easy to do that without modifying Mozzi's config in its library. Maybe later.
///
/// On Pot 1 I have set things up so you can change the pitch to some degree. There are 16
/// settings. Setting 8 (typically a bit to the left of due center) is the default setting.
/// Since Mozzi's sampling rate is 16384 Hz, this is about one octave above and twice as fast
/// as the traditional pitch, which normally corresponds to 8000 Hz. If you turn the knob
/// to the LEFT of this, Byte will get slower and lower in pitch. It does this by just playing
/// fewer times when Mozzi asks it to. It's pretty crude but it works. If you turn the knob to
/// the RIGHT, Byte will get higher in pitch but also change how it plays. This is because it
/// is incrementing the "t" variable by more and more (by default it's incremented by 1).
///
///
/// SET GRAINS TO MOZZI MODE. Sorry, no Grains mode.
///
/// You will need to install the Mozzi Library. You can do this from the Library Manager
/// in your Arduino IDE.
/// CONFIGURATION
///
/// IN 1 Pitch CV
/// IN 2 Bytebeat CV
/// IN 3 Auxilliary Variable 1 CV (x)
/// AUDIO IN (A) UNUSED
/// AUDIO OUT Out
/// DIGITAL OUT (D) Reset
///
/// POT 1 Pitch Scaling [Set the switch to MAN probably]
///
/// POT 2 Bytebeat [Set the switch to MAN probably]
///
/// POT 3 Volume
#include <math.h>
// FOR MORE BYTEBEAT EXAMPLES SEE
// http://viznut.fi/demos/unix/bytebeat_formulas.txt
//
// Test your bytebeats out first in HTML!
// https://greggman.com/downloads/examples/html5bytebeat/html5bytebeat.html
#define BYTEBEAT_1 \
t*(42&t>>10)
#define BYTEBEAT_2 \
t|t%255|t%257
#define BYTEBEAT_3 \
t*(((t>>11)&(t>>8))&(123&(t>>3)))
#define BYTEBEAT_4 \
t*(t>>((t>>9)|(t>>8))&(63&(t>>4)))
#define BYTEBEAT_5 \
(t>>6|t|t>>(t>>16))*10+((t>>11)&7)
#define BYTEBEAT_6 \
(t|(t>>9|t>>7))*t&(t>>11|t>>9)
#define BYTEBEAT_7 \
t*5&(t>>7)|t*3&(t*4>>10)
#define BYTEBEAT_8 \
(t>>7|t|t>>6)*10+4*(t&t>>13|t>>6)
#define BYTEBEAT_9 \
((t&4096)?((t*(t^t%255)|(t>>4))>>1):(t>>3)|((t&8192)?t<<2:t))
#define BYTEBEAT_10 \
((t*(t>>8|t>>9)&46&t>>8))^(t&t>>13|t>>6)
#define BYTEBEAT_11 \
(t*5&t>>7)|(t*3&t>>10)
#define BYTEBEAT_12 \
(int)(t/1e7*t*t+t)%127|t>>4|t>>5|t%127+(t>>16)|t
#define BYTEBEAT_13 \
((t/2*(15&(0x234568a0>>(t>>8&28))))|t/2>>(t>>11)^t>>12)+(t/16&t&24)
#define BYTEBEAT_14 \
(t&t%255)-(t*3&t>>13&t>>6)
#define BYTEBEAT_15 \
t>>4|t&((t>>5)/(t>>7-(t>>15)&-t>>7-(t>>15)))
#define BYTEBEAT_16 \
t*(((t>>9)&10)|((t>>11)&24)^((t>>10)&15&(t>>15)))
#define CV_POT_IN1 A7 // Note In, Pitch Scaling // Filter Cutoff
#define CV_POT_IN2 A6 // Filter Cutoff
#define CV_POT3 A4 // Resonance
#define CV_IN3 A2 // Amplitude CV
#define CV_AUDIO_IN A0 // Pitch Tune // Resonance CV
#define CV_AUDIO_OUT 9 // Out
#define CV_GATE_OUT 10 // [Unused]
#define RANDOM_PIN A5
#define CONTROL_RATE 64
#include <MozziGuts.h>
void setup()
{
pinMode(CV_GATE_OUT, INPUT);
startMozzi();
}
uint8_t triggered = false;
uint8_t x;
uint8_t frequency = 1;
uint8_t gain;
uint8_t expression;
uint32_t t = 0;
uint8_t oldExpression = 0;
uint8_t maxCount = 1;
uint8_t increment = 1;
void updateControl()
{
frequency = (mozziAnalogRead(CV_POT_IN1) >> 6) + 1;
if (frequency >= 8)
{
maxCount = 1;
increment = frequency - 7;
}
else
{
maxCount = 9 - frequency;
increment = 1;
}
gain = mozziAnalogRead(CV_POT3) >> 5; // 0...31
x = mozziAnalogRead(CV_IN3) >> 2; // 0...255
expression = mozziAnalogRead(CV_POT_IN2) >> 6; // 0...15
if (digitalRead(CV_GATE_OUT))
{
if (!triggered)
{
triggered = true;
t = 0;
}
}
else
{
triggered = false;
}
if (expression != oldExpression)
{
t = 0;
oldExpression = expression;
}
}
uint8_t count = 1;
int16_t last = 0;
int updateAudio()
{
count--;
if (count == 0)
{
count = maxCount;
// shift pitch
t += increment;
// select expression
uint8_t result;
switch(expression)
{
case 0: result = (uint8_t)(255 & (BYTEBEAT_1)); break;
case 1: result = (uint8_t)(255 & (BYTEBEAT_2)); break;
case 2: result = (uint8_t)(255 & (BYTEBEAT_3)); break;
case 3: result = (uint8_t)(255 & (BYTEBEAT_4)); break;
case 4: result = (uint8_t)(255 & (BYTEBEAT_5)); break;
case 5: result = (uint8_t)(255 & (BYTEBEAT_6)); break;
case 6: result = (uint8_t)(255 & (BYTEBEAT_7)); break;
case 7: result = (uint8_t)(255 & (BYTEBEAT_8)); break;
case 8: result = (uint8_t)(255 & (BYTEBEAT_9)); break;
case 9: result = (uint8_t)(255 & (BYTEBEAT_10)); break;
case 10: result = (uint8_t)(255 & (BYTEBEAT_11)); break;
case 11: result = (uint8_t)(255 & (BYTEBEAT_12)); break;
case 12: result = (uint8_t)(255 & (BYTEBEAT_13)); break;
case 13: result = (uint8_t)(255 & (BYTEBEAT_14)); break;
case 14: result = (uint8_t)(255 & (BYTEBEAT_15)); break;
case 15: result = (uint8_t)(255 & (BYTEBEAT_16)); break;
}
// convert to signed and change amplitude
last = ((result - (int16_t)128) * gain) >> 4; // gain should go 0...31
}
return last;
}
void loop()
{
audioHook();
}