Skip to content

Commit

Permalink
added m6
Browse files Browse the repository at this point in the history
  • Loading branch information
robstave committed Apr 4, 2019
1 parent 418c650 commit bc2f168
Show file tree
Hide file tree
Showing 16 changed files with 1,348 additions and 119 deletions.
11 changes: 7 additions & 4 deletions M0_Simple_Synth_04/M0_Simple_Synth_04.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

// M0 Trinket Synth - Exercise 04
// Create a Simple LFO controlled by CC
// Improved
// Improved - Set the counter independent of the interrupt. That way, for a very low
// LFO you do not have to wait until the next interrupt to do anything.
//
// Listens to the value of CC and adjusts the period of the dot on the M0
//
// Run this and adjust the CC value by experimentation
//


// Setup Onboard Dot
Expand All @@ -32,7 +35,7 @@ uint8_t state = 0;

uint16_t counterCompare = 100;

uint8_t lfoCCValue = 100;
uint8_t lfoCCValue = 7; // <--- set this to whatever your control seems to send


// Set timer TC4 to call the TC4_Handler every 1ms-ish (To Calculate)
Expand Down Expand Up @@ -105,8 +108,8 @@ void setup() {
setupTimer4();
}

# define maxLFO 30
# define minLFO 200
# define maxLFO 20 // small counter...decrease to make fastest rate a little faster
# define minLFO 300 // large counter...increase to make the lowest rate a little slower

// 0xB
void controlChange(byte channel, byte control, byte value) {
Expand Down
254 changes: 139 additions & 115 deletions M0_Simple_Synth_05/M0_Simple_Synth_05.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@
#include "pitchToFrequency.h"

// M0 Trinket Synth - Exercise 05
// make a sound controlled by CC and modulated (on/off) by another CC
// make a squarewave sound whose pitch is controlled by CC and is gated (on/off) by another CC acting as an LFO.
//

// IN PROGRESS
// Note some of the boilerplate/extra stuff as been moved to other .ino files. Arduino IDE just combines them
// with the dir filename.ino first and the remaining in alphabetical order.


// Setup Onboard Dot
#define NUMPIXELS 1 // Number of LEDs in strip

// The code is just doing the squarewaves at the moment with very simple counters.
// In the interrupt, we just count the number of ticks here until flipping the bit.

// LFO Counters. minLFO is actually a high number because its a larger tick to
# define maxLFO 40
# define minLFO 500


# define maxHF 70
# define minHF 800


// Here's how to control the LEDs from any two pins:
#define DATAPIN 7
#define CLOCKPIN 8
Expand All @@ -26,26 +38,39 @@ Adafruit_DotStar strip = Adafruit_DotStar(
#endif


uint16_t counter = 0;
uint8_t state = 0;
// Control channels we are listening for.
// Run this and watch the serial port while twisting a knob. Note the values and set them here and recompile/reload the sketch.
uint8_t CC1 = 7;
uint8_t CC2 = 114;


volatile uint16_t counter = 0;
volatile uint8_t state = 0; // LFO Bit On/Off
volatile uint16_t counterCompare = 100;

uint16_t counterCompare = 100;
volatile uint16_t counterHF = 0;
volatile uint8_t stateHF = 0; // HF Bit On/Off
volatile uint16_t counterCompareHF = 100;

volatile uint8_t red = 0; // Store off Color
volatile uint8_t green = 0;

uint8_t lfoCCValue = 100;
// Not really needed, but basically avoids doing anything on repeat messages
volatile uint8_t lfoCC1Value = 100;
volatile uint8_t lfoCC2Value = 100;


// Set timer TC4 to call the TC4_Handler every 1ms-ish (To Calculate)
// taken from
// http://forum.arduino.cc/index.php?topic=599151.0
void setupTimer4() {
void setupTimer4_5() {
// Feed GCLK0 to TC4 and TC5
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK0 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization

TC4->COUNT16.CC[0].reg = 500; // Set the TC4 CC0 register as the TOP value in match frequency mode
TC4->COUNT16.CC[0].reg = 100; // Set the TC4 CC0 register as the TOP value in match frequency mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
Expand All @@ -62,6 +87,26 @@ void setupTimer4() {

TC4->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC4
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization



TC5->COUNT16.CC[0].reg = 10; // Set the TC5 CC0 register as the TOP value in match frequency mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC5_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC5 to 0 (highest)
NVIC_EnableIRQ(TC5_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

TC5->COUNT16.INTFLAG.reg |= TC_INTFLAG_OVF; // Clear the interrupt flags
TC5->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC5 interrupts

TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCSYNC_PRESC | // Reset timer on the next prescaler clock
TC_CTRLA_PRESCALER_DIV64 | // Set prescaler to 64, 48MHz/64 = ???46.875kHz //TODO fix this
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC5 into match frequency (MFRQ) mode
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC5
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
}


Expand All @@ -72,65 +117,131 @@ void TC4_Handler() // Interrupt Service
{
// Put your timer overflow (OVF) code here....


if (counter > counterCompare) {

// LFO CODE. When we hit the counter, flip the state bool (and the color of the light)

if (state % 2 == 0) {
strip.setPixelColor(0, 0, 0, 0); //set the pixel colors
red = 0;
} else {
strip.setPixelColor(0, 0xFF, 0, 0); //set the pixel colors
red = 0xFF;
}

strip.setPixelColor(0, red, 0, 0); //set the pixel colors

strip.show();
state++;
counter = 0;
}

counter++;

TC4->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag
}
}

// Serial.print(" up:");
// Serial.println(counter);

TC4->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag
void TC5_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
// Check for overflow (OVF) interrupt
if (TC5->COUNT16.INTFLAG.bit.OVF && TC5->COUNT16.INTENSET.bit.OVF)
{
// Put your timer overflow (OVF) code here....

// Higher Frequency Interrupt...basically the same thing/
// We could flip a digital pin, but the board has an analog out.
//
// Check the LFO state and turn off, on accordingly.

if (counterHF > counterCompareHF) {

if (stateHF % 2 == 0) {
analogWrite(A0, 0);
} else {
if (state % 2 == 0) {
analogWrite(A0, 255);
} else {
analogWrite(A0, 0);
}
}
stateHF++;
counterHF = 0;
}
counterHF++;

TC5->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag
}
}


void setup() {
Serial.begin(115200);
Serial.println("Setting up:");
Serial.println("Setting up: Version 05");

strip.begin(); // Initialize pins for output
strip.show(); // Turn all LEDs off ASAP

setupTimer4();
setupTimer4_5();

}


// Wrap Map into a function that is a little 1-logish. Simple break it a bit in ranges.
// Assumes a midi note in the range of 0-127 and makes it kinda 1-log(x) without a whole lot of
// processing.
//
//
int mapMidiLowBudget(int value, int v1, int v2) {
int octave = v1 - v2;
int point1 = v1 - (octave / 2) ;

if (value < 33) {
return map(value, 0, 32, v1, point1);
} else {
return map(value, 32, 127, point1, v2);
}
}

# define maxLFO 30
# define minLFO 200

// 0xB
void controlChange(byte channel, byte control, byte value) {

if (lfoCCValue == value) {
return;
if (control == CC1) {
if (lfoCC1Value == value) {
return;
}
lfoCC1Value = value;
//counterCompare = map(value, 0, 127, minLFO, maxLFO);
counterCompare = mapMidiLowBudget(value, minLFO, maxLFO);

Serial.print("counterCompare:");
Serial.println(counterCompare);
}
lfoCCValue = value;

counterCompare = map(value, 0, 127, minLFO, maxLFO);


Serial.print("counterCompare:");
Serial.println(counterCompare);

logData(0xB, channel, control, value) ;
if (control == CC2) {
if (lfoCC2Value == value) {
return;
}
lfoCC2Value = value;
//counterCompareHF = map(value, 0, 127, minHF, maxHF);
counterCompareHF = mapMidiLowBudget(value, minHF, maxHF);

}

logData(0xB, channel, control, value) ; // optinonal
}


void loop() {


Serial.println("Enter Loop:");

initSequence(); // Blinky intro



while (true) {
// Midi packet taken from
// midiEventPacket_t rx = MidiUSB.read();
Expand All @@ -147,8 +258,6 @@ void loop() {
case 0:
break; //No pending events



case 0xB:
controlChange(
rx.byte1 & 0xF, //channel
Expand All @@ -165,88 +274,3 @@ void loop() {
}
}
}


const char* pitch_name(byte pitch) {
static const char* names[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
return names[pitch % 12];
}

int pitch_octave(byte pitch) {
return (pitch / 12) - 1;
}


void logData(byte header, byte channel, byte byte2, byte byte3) {

switch (header) {
case 0:
return;


case 0x9:

Serial.print("Note On: ");
Serial.println(byte2);
Serial.print(pitch_name(byte2));
Serial.print(pitch_octave(byte2));
Serial.print(", channel=");
Serial.print(channel);
Serial.print(", velocity=");
Serial.println(byte3);
break;

case 0x8:
Serial.print("Note Off: ");
Serial.println(byte2);
Serial.print(pitch_name(byte2));
Serial.print(pitch_octave(byte2));
Serial.print(", channel=");
Serial.print(channel);
Serial.print(", velocity=");
Serial.println(byte3);

break;

case 0xB:
Serial.print("Control change: control=");
Serial.print(byte2);
Serial.print(", value=");
Serial.print(byte3);
Serial.print(", channel=");
Serial.println(channel);
break;

default:
Serial.print("Unhandled MIDI message: ");
Serial.print(header, HEX);
Serial.print("-");
Serial.print(channel, HEX);
Serial.print("-");
Serial.print(byte2, HEX);
Serial.print("-");
Serial.println(byte3, HEX);

break;

}
}


// Pretty sequence to know it started up
void initSequence() {
strip.setPixelColor(0, 0x1F0000); // red
strip.show();
delay(500);

strip.setPixelColor(0, 0x001F00); // green
strip.show();
delay(050);

strip.setPixelColor(0, 0x00001F); // blue
strip.show();
delay(500);

strip.setPixelColor(0, 0x000000); // blue
strip.show();
}
Loading

0 comments on commit bc2f168

Please sign in to comment.