#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Mux.h>
using namespace admux;
Mux mux1(Pin(A14, INPUT, PinType::Analog), Pinset(1, 2, 3));
// GUItool: begin automatically generated code
AudioInputI2S in; //xy=105,63
AudioEffectFade fade1;
AudioEffectFade fade2;
AudioEffectGranular granular1;
AudioEffectGranular granular2;
AudioEffectGranular granular3;
AudioEffectFreeverbStereo freeverbs1;
AudioEffectEnvelope envelope1;
AudioEffectMultiply multiply1;
AudioEffectMultiply multiply2;
AudioEffectDelay delay1;
AudioSynthWaveform waveform1;
AudioSynthWaveformDc dc1;
AudioSynthWaveform waveform2;
AudioSynthWaveformDc dc2;
AudioMixer4 mixer1;
AudioMixer4 mixerL;
AudioMixer4 mixerR;
AudioMixer4 revSend1;
AudioMixer4 granularMixL;
AudioMixer4 granularMixR;
AudioMixer4 mixer2grain2;
AudioMixer4 mixer2grain3;
AudioMixer4 mixerDc1;
AudioMixer4 mixerDc2;
AudioMixer4 delaySend1;
AudioAnalyzePeak peak1; //xy=278,108
AudioRecordQueue queue1; //xy=281,63
AudioPlaySdRaw playRaw1; //xy=302,157
AudioOutputI2S out; //xy=470,120
AudioConnection patchCord1(in, 0, queue1, 0);
AudioConnection patchCord2(in, 0, peak1, 0);
AudioConnection patchCord3(playRaw1, 0, fade1, 0);
AudioConnection patchCord4(playRaw1, 0, fade2, 0);
AudioConnection patchCord5(fade1, 0, mixer1, 0);
AudioConnection patchCord6(fade2, 0, mixer1, 1);
AudioConnection patchCord7(mixer1, 0, granular1, 0);
AudioConnection patchCord8(granular1, 0, revSend1, 0);
AudioConnection patchCord10(revSend1, 0, freeverbs1, 0);
AudioConnection patchCord11(granular1, 0, mixerL, 0);
AudioConnection patchCord12(granular1, 0, mixerR, 0);
AudioConnection patchCord13(freeverbs1, 0, mixerL, 1);
AudioConnection patchCord14(freeverbs1, 1, mixerR, 1);
AudioConnection patchCord15(mixerL, 0, out, 0);
AudioConnection patchCord16(mixerR, 0, out, 1);
// Granular Mix
AudioConnection patchCord17(granular1, 0, mixer2grain2, 0);
AudioConnection patchCord18(granular1, 0, mixer2grain3, 0);
AudioConnection patchCord19(mixer2grain2, 0, granular2, 0);
AudioConnection patchCord20(mixer2grain3, 0, granular3, 0);
AudioConnection patchCord21(multiply2, 0, granularMixL, 0);
AudioConnection patchCord22(multiply2, 0, granularMixR, 0);
AudioConnection patchCord23(multiply1, 0, granularMixL, 1);
AudioConnection patchCord24(multiply1, 0, granularMixR, 1);
AudioConnection patchCord25(granularMixL, 0, mixerL, 2);
AudioConnection patchCord26(granularMixR, 0, mixerR, 2);
// Delay
AudioConnection patchCordDl1(granularMixL, 0, delaySend1, 0);
AudioConnection patchCordDl2(granularMixR, 0, delaySend1, 1);
AudioConnection patchCordDl3(delaySend1, 0, delay1, 0);
AudioConnection patchCordDl4(delay1, 0, granularMixL, 2);
AudioConnection patchCordDl5(delay1, 1, granularMixL, 3);
AudioConnection patchCordDl6(delay1, 2, granularMixR, 2);
AudioConnection patchCordDl7(delay1, 3, granularMixR, 3);
// VCA
AudioConnection patchCord27(granular3, 0, multiply1, 0);
AudioConnection patchCord28(waveform1, 0, mixerDc1, 0);
AudioConnection patchCord29(dc1, 0, mixerDc1, 1);
AudioConnection patchCord30(mixerDc1, 0, multiply1, 1);
AudioConnection patchCord31(granular2, 0, multiply2, 0);
AudioConnection patchCord32(waveform2, 0, mixerDc2, 0);
AudioConnection patchCord33(dc2, 0, mixerDc2, 1);
AudioConnection patchCord34(mixerDc2, 0, multiply2, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=265,212
// GUItool: end automatically generated code
// For a stereo recording version, see this forum thread:
// https://forum.pjrc.com/threads/46150?p=158388&viewfull=1#post158388
// A much more advanced sound recording and data logging project:
// https://github.com/WMXZ-EU/microSoundRecorder
// https://github.com/WMXZ-EU/microSoundRecorder/wiki/Hardware-setup
// https://forum.pjrc.com/threads/52175?p=185386&viewfull=1#post185386
// Bounce objects to easily and reliably read the buttons
Bounce buttonRecord = Bounce(0, 3);
Bounce buttonStopRec = Bounce(4, 3);
Bounce buttonGrain2 = Bounce(28, 3);
Bounce buttonGrain3 = Bounce(29, 3);
Bounce changeWaveform = Bounce(30, 15);
Bounce changeWaveform2 = Bounce(30, 15);
#define GRANULAR_MEMORY_SIZE 12800 // enough for 290 ms at 44.1 kHz
int16_t granularMemory[GRANULAR_MEMORY_SIZE];
#define GRANULAR_MEMORY_SIZE2 6000 // enough for 290 ms at 44.1 kHz
int16_t granularMemory2[GRANULAR_MEMORY_SIZE2];
#define GRANULAR_MEMORY_SIZE3 6000 // enough for 290 ms at 44.1 kHz
int16_t granularMemory3[GRANULAR_MEMORY_SIZE3];
// which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// Remember which mode we're doing
enum Mode {
stopped,
recording,
playing,
};
Mode mode = stopped;
Mode mode1 = stopped;
// The file where data is recorded
File frec;
bool State = false;
bool Stateenv = false;
Mode playmode = playing;
int playmode2 = 0;
unsigned long previousMillis = 0;
unsigned long interval = 500;
unsigned long interval1 = interval - 50;
unsigned long intervalenv = 500;
int current_waveform = 0;
int current_waveform2 = 0;
void setup() {
granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE);
granular2.begin(granularMemory2, GRANULAR_MEMORY_SIZE2);
granular3.begin(granularMemory3, GRANULAR_MEMORY_SIZE3);
granular1.beginPitchShift(1000);
mixer1.gain(0, 0.8);
mixer1.gain(1, 0.8);
mixer1.gain(2, 0.8);
mixerL.gain(0, 0.8);
mixerR.gain(0, 0.8);
mixerL.gain(1, 0.8);
mixerR.gain(1, 0.8);
mixerL.gain(2, 0.8);
mixerR.gain(2, 0.8);
mixer2grain2.gain(0, 0);
mixer2grain3.gain(0, 0);
granularMixL.gain(0, 0.8);
granularMixR.gain(0, 0.4);
granularMixL.gain(1, 0.4);
granularMixR.gain(1, 0.8);
granularMixL.gain(2, 0.5);
granularMixR.gain(2, 0.5);
granularMixL.gain(3, 0.5);
granularMixR.gain(3, 0.5);
mixerDc1.gain(0, 1);
mixerDc1.gain(1, 1);
mixerDc2.gain(0, 1);
mixerDc2.gain(1, 1);
// Configure the pushbutton pins
pinMode(0, INPUT_PULLUP);
pinMode(28, INPUT_PULLUP);
pinMode(29, INPUT_PULLUP);
pinMode(30, INPUT_PULLUP);
pinMode(33, OUTPUT);
// Audio connections require memory, and the record queue
// uses this memory to buffer incoming audio.
AudioMemory(250);
// Enable the audio shield, select input, and enable output
sgtl5000_1.enable();
sgtl5000_1.inputSelect(myInput);
sgtl5000_1.volume(1);
// Initialize the SD card
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here if no SD card, but print a message
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
if (SD.exists("RECORD.RAW")) {
// The SD library writes new data to the end of the
// file, so to start a new recording, the old file
// must be deleted before new data is written.
SD.remove("RECORD.RAW");
}
current_waveform = WAVEFORM_SINE;
waveform1.begin(current_waveform);
waveform2.begin(current_waveform2);
}
void loop() {
Serial.println(AudioMemoryUsageMax());
for (byte i = 0; i < mux1.channelCount(); i++) {
mux1.channel(i);
// allow 50 us for signals to stablize
delayMicroseconds(50);
}
env1();
env2();
grain();
grain2();
grain3();
DL();
reverb();
vca1();
vca2();
looplength();
// First, read the buttons
buttonRecord.update();
buttonStopRec.update();
///////////////// 1st Sample
// Respond to button presses
if (buttonRecord.fallingEdge()) {
stopPlaying1();
stopPlaying2();
startRecording();
playmode = recording;
}
if (buttonRecord.risingEdge()) {
stopRecording();
playmode = playing;
}
if (playmode == playing) {
//play1
if (State == true) {
stopPlaying2();
if (mode == stopped) {
startPlaying1();
}
}
if (State == false) {
stopPlaying1();
if (mode1 == stopped) {
startPlaying2();
}
}
}
// If we're playing or recording, carry on...
if (mode == recording) {
continueRecording();
}
if (mode == playing) {
continuePlaying1();
}
if (mode1 == playing) {
continuePlaying2();
}
}
////////////////// 1st Sample
void startRecording() {
Serial.println("startRecording");
if (SD.exists("RECORD.RAW")) {
// The SD library writes new data to the end of the
// file, so to start a new recording, the old file
// must be deleted before new data is written.
SD.remove("RECORD.RAW");
}
frec = SD.open("RECORD.RAW", FILE_WRITE);
if (frec) {
queue1.begin();
mode = recording;
}
}
void continueRecording() {
if (queue1.available() >= 2) {
byte buffer[512];
// Fetch 2 blocks from the audio library and copy
// into a 512 byte buffer. The Arduino SD library
// is most efficient when full 512 byte sector size
// writes are used.
memcpy(buffer, queue1.readBuffer(), 256);
queue1.freeBuffer();
memcpy(buffer + 256, queue1.readBuffer(), 256);
queue1.freeBuffer();
// write all 512 bytes to the SD card
//elapsedMicros usec = 0;
frec.write(buffer, 512);
// Uncomment these lines to see how long SD writes
// are taking. A pair of audio blocks arrives every
// 5802 microseconds, so hopefully most of the writes
// take well under 5802 us. Some will take more, as
// the SD library also must write to the FAT tables
// and the SD card controller manages media erase and
// wear leveling. The queue1 object can buffer
// approximately 301700 us of audio, to allow time
// for occasional high SD card latency, as long as
// the average write time is under 5802 us.
//Serial.print("SD write, us=");
//Serial.println(usec);
}
}
void stopRecording() {
Serial.println("stopRecording");
queue1.end();
if (mode == 1) {
while (queue1.available() > 0) {
frec.write((byte*)queue1.readBuffer(), 256);
queue1.freeBuffer();
}
frec.close();
}
mode = stopped;
}
////////// Playing1
void startPlaying1() {
playRaw1.play("RECORD.RAW");
mode = playing;
}
void continuePlaying1() {
if (!playRaw1.isPlaying()) {
playRaw1.stop();
mode = stopped;
}
}
void stopPlaying1() {
if (mode == 2) playRaw1.stop();
mode = 0;
}
////////// playing2
void startPlaying2() {
playRaw1.play("RECORD.RAW");
mode1 = 2;
}
void continuePlaying2() {
if (!playRaw1.isPlaying()) {
playRaw1.stop();
mode1 = 0;
}
}
void stopPlaying2() {
if (mode1 == 2) playRaw1.stop();
mode1 = 0;
}
////////////// Fades
void env1() {
if (Stateenv == false) {
fade1.fadeOut(50);
} else {
fade1.fadeIn(50);
}
}
void env2() {
if (Stateenv == true) {
fade2.fadeOut(50);
} else {
fade2.fadeIn(50);
}
}
/////////// Grain for main loop
void grain() {
float FaderPitch = mux1.read(1) / 1023.0;
// Continuously adjust the speed, based on the A3 pot
float ratio;
//ratio = powf(2.0, knobA11 * 6.0 - 3.0); // 0.5 to 2.0
ratio = powf(2.0, FaderPitch * 2.0 - 1.0); // 0.125 to 8.0 -- uncomment for far too much range!
granular1.setSpeed(ratio);
delayMicroseconds(30);
}
/////////// Grain freeze 1
void grain2() {
buttonGrain2.update();
//Serial.println(millis());
float FaderFreeze1Pitch = mux1.read(2) / 1023.0;
//float FaderFreeze1Length = mux1.read(3) / 1023.0;
// Button 0 starts Freeze effect
if (buttonGrain2.fallingEdge()) {
mixer2grain2.gain(0, 1);
// float msec2 = 50.0 + (FaderFreeze1Length * 150.0);
float msec2 = 100;
granular2.beginFreeze(msec2);
Serial.print("Begin granular freeze using ");
Serial.print(msec2);
Serial.println(" grains");
}
if (buttonGrain2.risingEdge()) {
mixer2grain2.gain(0, 0);
granular2.stop();
}
float ratio2;
//ratio2 = powf(2.0, knobA10 * 2.0 - 1.0); // 0.5 to 2.0
ratio2 = powf(2.0, FaderFreeze1Pitch * 2.0 - 1.0); // 0.125 to 8.0 -- uncomment for far too much range!
granular2.setSpeed(ratio2);
}
//////////// Grainfreeze2
void grain3() {
buttonGrain3.update();
float FaderFreeze2Pitch = mux1.read(3) / 1023.0;
// float FaderFreeze2Length = mux1.read(3) / 1023.0;
// Button 0 starts Freeze effect
if (buttonGrain3.fallingEdge()) {
mixer2grain3.gain(0, 1);
//float msec3 = 50.0 + (FaderFreeze2Length * 130.0);
float msec3 = 100;
granular3.beginFreeze(msec3);
Serial.print("Begin granular freeze using ");
Serial.print(msec3);
Serial.println(" grains");
}
if (buttonGrain3.risingEdge()) {
mixer2grain3.gain(0, 0);
granular3.stop();
}
float ratio3;
//ratio2 = powf(2.0, knobA10 * 2.0 - 1.0); // 0.5 to 2.0
ratio3 = powf(2.0, FaderFreeze2Pitch * 2.0 - 1.0); // 0.125 to 8.0 -- uncomment for far too much range!
granular3.setSpeed(ratio3);
}
///////////// Delay
void DL(){
delaySend1.gain(0, 0.3);
delaySend1.gain(1, 0.3);
delay1.delay(0, 300);
delay1.delay(1, 500);
delay1.delay(2, 200);
delay1.delay(3, 400);
}
///////////// Reverb
void reverb() {
//float KnobA10 = (float)analogRead(A10) / 1023.0;
freeverbs1.roomsize(0.8);
freeverbs1.damping(1);
revSend1.gain(0, 0);
//revSend1.gain(1, KnobA10);
//revSend1.gain(2, KnobA10);
}
///////////// VCA
void vca1() {
float fq1 = mux1.read(4) / 20;
changeWaveform.update();
waveform1.amplitude(1);
waveform1.frequency(fq1 + 0.1);
dc1.amplitude(0);
if (changeWaveform.fallingEdge()) {
switch (current_waveform) {
case WAVEFORM_SINE:
current_waveform = WAVEFORM_SAWTOOTH;
Serial.println("Square");
break;
case WAVEFORM_SAWTOOTH:
current_waveform = WAVEFORM_SAMPLE_HOLD;
Serial.println("S&H");
break;
case WAVEFORM_SAMPLE_HOLD:
current_waveform = WAVEFORM_SINE;
Serial.println("Sine");
break;
}
AudioNoInterrupts();
waveform1.begin(current_waveform);
AudioInterrupts();
}
}
///////////
void vca2() {
float fq1 = mux1.read(4) / 20;
changeWaveform2.update();
waveform2.amplitude(1);
waveform2.frequency(fq1 + 0.1);
dc2.amplitude(0);
if (changeWaveform2.fallingEdge()) {
switch (current_waveform2) {
case WAVEFORM_SINE:
current_waveform2 = WAVEFORM_SAWTOOTH;
Serial.println("Square2");
break;
case WAVEFORM_SAWTOOTH:
current_waveform2 = WAVEFORM_SAMPLE_HOLD;
Serial.println("S&H2");
break;
case WAVEFORM_SAMPLE_HOLD:
current_waveform2 = WAVEFORM_SINE;
Serial.println("Sine2");
break;
}
AudioNoInterrupts();
waveform2.begin(current_waveform2);
AudioInterrupts();
}
}
void looplength() {
unsigned long currentMillis = millis();
interval = map (mux1.read(5), 0, 1023, 50, playRaw1.lengthMillis());
// interval = map (analogRead(A10), 0, 1023, 50, playRaw1.lengthMillis());
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
State = !State;
}
if (currentMillis - previousMillis >= interval1) {
Stateenv = !Stateenv;
}
if (State == HIGH){
digitalWrite(33, HIGH);
} else {
digitalWrite(33,LOW);
}
}