Initial commit
commit
ddad5492e1
|
@ -0,0 +1,41 @@
|
||||||
|
// Basic demo for configuring the MCP4728 4-Channel 12-bit I2C DAC
|
||||||
|
#include <Adafruit_MCP4728.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
Adafruit_MCP4728 mcp;
|
||||||
|
|
||||||
|
float xlog = 0.5;
|
||||||
|
float r = 3.783423;
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial)
|
||||||
|
delay(10); // will pause Zero, Leonardo, etc until serial console opens
|
||||||
|
|
||||||
|
Serial.println("Adafruit MCP4728 test!");
|
||||||
|
|
||||||
|
// Try to initialize!
|
||||||
|
if (!mcp.begin(0x64)) {
|
||||||
|
Serial.println("Failed to find MCP4728 chip");
|
||||||
|
while (1) {
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mcp.setChannelValue(MCP4728_CHANNEL_A, 4095);
|
||||||
|
mcp.setChannelValue(MCP4728_CHANNEL_B, 2048);
|
||||||
|
mcp.setChannelValue(MCP4728_CHANNEL_C, 1024);
|
||||||
|
mcp.setChannelValue(MCP4728_CHANNEL_D, 0);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int pot = analogRead(A0);
|
||||||
|
r = (float)pot / 1024.0 + 3.0;
|
||||||
|
xlog = r * xlog * (1 - xlog);
|
||||||
|
int cv = round(xlog * 4095.0);
|
||||||
|
mcp.setChannelValue(MCP4728_CHANNEL_A, cv);
|
||||||
|
// delay(100);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
Looptober 2024
|
||||||
|
==============
|
||||||
|
|
||||||
|
Arduino code for my Looptober 24 stuff
|
||||||
|
|
||||||
|
Music to be found at [my Funkwhale server](https://music.mikelynch.org/)
|
|
@ -0,0 +1,168 @@
|
||||||
|
// We Wish You a Merry Christmas
|
||||||
|
#include <Adafruit_MCP4728.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
Adafruit_MCP4728 mcp;
|
||||||
|
|
||||||
|
|
||||||
|
float tuning[16];
|
||||||
|
// 0 = A, 8 = F (tonic)
|
||||||
|
|
||||||
|
int m1[] = { 3, 8, 8, 10, 8, 7, 5, 5, 5, 10, 10, 12, 10, 8, 7, 3, 7, 12, 12, 13, 12, 10, 8, 5, 3, 3, 5, 10, 7, 8, 3, 8, 8, 8, 7, 7, 8, 7, 5, 3, 10, 12, 10, 10, 8, 8, 15, 3, 3, 3, 5, 10, 7, 8 };
|
||||||
|
int s1[] = { 0, 2, 4, 5, 6, 7, 8, 10, 12, 14, 16, 17, 18, 19, 20, 22, 24, 26, 28, 29, 30, 31, 32, 34, 36, 37, 38, 40, 42, 44, 48, 50, 52, 54, 56, 60, 62, 64, 66, 68, 72, 74, 76, 77, 78, 79, 80, 82, 84, 85, 86, 88, 90, 92 };
|
||||||
|
float d1[] = { 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 4 };
|
||||||
|
|
||||||
|
int m2[] = { 8, 1, 2, 3, 4, 5, 0, 1, 3, 8, 8, 3, 5, 7, 8, 7, 0, 1, 3, 8 };
|
||||||
|
int s2[] = { 2, 8, 14, 20, 26, 32, 36, 38, 42, 44, 50, 56, 62, 68, 74, 80, 84, 86, 90, 92 };
|
||||||
|
float d2[] = { 6, 6, 6, 6, 6, 4, 2, 4, 2, 6, 6, 6, 6, 6, 6, 4, 2, 4, 2, 4 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// int m1[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
|
||||||
|
// int s1[] = { 0, 2, 4, 6, 8, 10, 12, 14 };
|
||||||
|
// float d1[] = { 1.0, 0.5, 1.0, 0.5, 1.0, 0.5, 1.0, 0.5 };
|
||||||
|
// int m2[] = { 0, 4, 7, 12, 0, 4, 7, 12, 0, 4, 7, 12, 0, 4, 7, 12 };
|
||||||
|
// int s2[] = { 0, 1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||||
|
// float d2[] = { 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 };
|
||||||
|
|
||||||
|
|
||||||
|
float gate = 0.5;
|
||||||
|
int bpm = 320;
|
||||||
|
float beat_s = 60.0 / (float)bpm;
|
||||||
|
int beat = round(1000.0 * beat_s);
|
||||||
|
|
||||||
|
// count_in = number of beats since t0 to wait before we startt playing
|
||||||
|
// repeat = number of beats to repeat - could be computed from the sequence data
|
||||||
|
|
||||||
|
// From here on, all times are in milliseconds to head off floating point errors
|
||||||
|
|
||||||
|
long count_in = 4 * beat;
|
||||||
|
int repeat = 96;
|
||||||
|
|
||||||
|
|
||||||
|
float voltrange = 5.0;
|
||||||
|
float octave = 4096.0 / voltrange; // number of DAC steps in an octave
|
||||||
|
float mod_b = 3.141592653589793 / 4.0;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int s = -1;
|
||||||
|
bool playing = false;
|
||||||
|
bool looped = false;
|
||||||
|
long play = 0;
|
||||||
|
long rel = 0;
|
||||||
|
long last = 0;
|
||||||
|
long init = 0;
|
||||||
|
int *melody;
|
||||||
|
int *start;
|
||||||
|
float *duration;
|
||||||
|
int len = 0;
|
||||||
|
MCP4728_channel_t pitch;
|
||||||
|
MCP4728_channel_t gate;
|
||||||
|
} sequencer;
|
||||||
|
|
||||||
|
sequencer seq1, seq2;
|
||||||
|
long start_time;
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial)
|
||||||
|
delay(10); // will pause Zero, Leonardo, etc until serial console opens
|
||||||
|
|
||||||
|
if (!mcp.begin(0x64)) {
|
||||||
|
Serial.println("Failed to find MCP4728 chip");
|
||||||
|
while (1) {
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
Serial.println("MCP4728 initialised");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float n0 = 0;
|
||||||
|
for( int i = 0; i < 16; i++ ) {
|
||||||
|
tuning[i] = round(n0 + octave * (float)i / 12.0);
|
||||||
|
}
|
||||||
|
long now = millis();
|
||||||
|
start_time = now;
|
||||||
|
seq1.last = now;
|
||||||
|
seq1.pitch = MCP4728_CHANNEL_A;
|
||||||
|
seq1.gate = MCP4728_CHANNEL_B;
|
||||||
|
seq1.melody = m1;
|
||||||
|
seq1.start = s1;
|
||||||
|
seq1.duration = d1;
|
||||||
|
seq1.len = sizeof(m1) / sizeof(m1[0]);
|
||||||
|
|
||||||
|
times_to_ms(seq1);
|
||||||
|
|
||||||
|
seq2.last = now;
|
||||||
|
seq2.pitch = MCP4728_CHANNEL_C;
|
||||||
|
seq2.gate = MCP4728_CHANNEL_D;
|
||||||
|
seq2.melody = m2;
|
||||||
|
seq2.duration = d2;
|
||||||
|
seq2.start = s2;
|
||||||
|
seq2.len = sizeof(m2) / sizeof(m2[0]);
|
||||||
|
|
||||||
|
times_to_ms(seq2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void times_to_ms(sequencer& seq) {
|
||||||
|
for( int i = 0; i < seq.len; i++ ) {
|
||||||
|
seq.start[i] *= beat;
|
||||||
|
seq.duration[i] = (float)beat * seq.duration[i] * 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
long now = millis();
|
||||||
|
long t = now - start_time;
|
||||||
|
long beats = -1;
|
||||||
|
if( t >= count_in ) {
|
||||||
|
beats = (t - count_in) % (beat * repeat);
|
||||||
|
runSequencer(seq1, t, beats);
|
||||||
|
runSequencer(seq2, t, beats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runSequencer(sequencer& seq, long now, long beats) {
|
||||||
|
int next = seq.s + 1;
|
||||||
|
int start;
|
||||||
|
|
||||||
|
if( seq.playing ) {
|
||||||
|
if( now > seq.rel ) {
|
||||||
|
mcp.setChannelValue(seq.gate, 0);
|
||||||
|
seq.playing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( next > seq.len - 1 ) {
|
||||||
|
seq.s = -1;
|
||||||
|
seq.looped = true;
|
||||||
|
return; // don't start the loop yet
|
||||||
|
} else {
|
||||||
|
start = seq.start[next];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( seq.looped ) { // reached the end and waiting for the start of the bar
|
||||||
|
if( beats < seq.last ) {
|
||||||
|
seq.looped = false; // bar has restarted, start waiting
|
||||||
|
seq.s = -1;
|
||||||
|
next = 0;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seq.last = beats;
|
||||||
|
|
||||||
|
if( beats >= start ) {
|
||||||
|
seq.s = next;
|
||||||
|
seq.rel = now + seq.duration[seq.s];
|
||||||
|
if( seq.melody[seq.s] > -1 ) {
|
||||||
|
mcp.setChannelValue(seq.pitch, tuning[seq.melody[seq.s]]);
|
||||||
|
mcp.setChannelValue(seq.gate, 4095);
|
||||||
|
}
|
||||||
|
seq.playing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue