117 lines
2.8 KiB
C++
117 lines
2.8 KiB
C++
// Basic demo for configuring the MCP4728 4-Channel 12-bit I2C DAC
|
|
#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 d1[] = { 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 4 };
|
|
int m2[] = { -1, 8, 1, 2, 3, 4, 5, 0, 1, 3, 8, 8, 3, 5, 7, 8, 7, 0, 1, 3, 8 };
|
|
int d2[] = { 2, 6, 6, 6, 6, 6, 4, 2, 4, 2, 6, 6, 6, 6, 6, 6, 4, 2, 4, 2, 4 };
|
|
float gate = 0.5;
|
|
int bpm = 240;
|
|
float beat_s = 60.0 / (float)bpm;
|
|
int beat_m = round(1000.0 * beat_s);
|
|
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 = 0;
|
|
bool noteOn = false;
|
|
long play = 0;
|
|
long rel = 0;
|
|
long last = 0;
|
|
long init = 0;
|
|
int *melody;
|
|
int *duration;
|
|
int len = 0;
|
|
MCP4728_channel_t pitch;
|
|
MCP4728_channel_t gate;
|
|
} sequencer;
|
|
|
|
sequencer seq1, seq2;
|
|
|
|
|
|
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");
|
|
}
|
|
|
|
mcp.setChannelValue(MCP4728_CHANNEL_B, 0);
|
|
|
|
float n0 = 0;
|
|
for( int i = 0; i < 16; i++ ) {
|
|
tuning[i] = round(n0 + octave * (float)i / 12.0);
|
|
}
|
|
long now = millis();
|
|
seq1.last = now;
|
|
seq1.pitch = MCP4728_CHANNEL_A;
|
|
seq1.gate = MCP4728_CHANNEL_B;
|
|
seq1.melody = m1;
|
|
seq1.duration = d1;
|
|
seq1.len = sizeof(m1) / sizeof(m1[0]);
|
|
|
|
seq2.last = now;
|
|
seq2.pitch = MCP4728_CHANNEL_C;
|
|
seq2.gate = MCP4728_CHANNEL_D;
|
|
seq2.melody = m2;
|
|
seq2.duration = d2;
|
|
seq2.len = sizeof(m2) / sizeof(m2[0]);
|
|
|
|
}
|
|
|
|
|
|
void loop() {
|
|
long now = millis();
|
|
runSequencer(seq1, now);
|
|
runSequencer(seq2, now);
|
|
}
|
|
|
|
void runSequencer(sequencer& seq, long now) {
|
|
if( seq.noteOn ) {
|
|
if( now - seq.last > seq.rel ) {
|
|
noteOff(seq);
|
|
seq.last = now;
|
|
seq.play = 0; // no gate for now
|
|
seq.noteOn = false;
|
|
seq.s += 1;
|
|
if( seq.s > seq.len ) {
|
|
seq.s = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if( now - seq.last > seq.play ) {
|
|
noteOn(seq, seq.melody[seq.s]);
|
|
seq.last = now;
|
|
seq.rel = beat_m * seq.duration[seq.s];
|
|
seq.noteOn = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void noteOn(sequencer seq, int note) {
|
|
if( note > -1 ) {
|
|
mcp.setChannelValue(seq.pitch, tuning[note]);
|
|
mcp.setChannelValue(seq.gate, 4095);
|
|
}
|
|
}
|
|
|
|
void noteOff(sequencer seq) {
|
|
mcp.setChannelValue(seq.gate, 0);
|
|
}
|