Hi, I've been working on this project on and off for a few years give or take, and finally have some hardware together:
mega 2560
serLCD
SPI pots
2 analog inputs, 2 digital inputs
I want to make a device that allows user entry of parameters for a polyphonic tone player. Musical mode, key, scale, etc; then 'play' to hear polyphony. I enable my tone player array as follows:
NotePlayer[0].begin(9);
NotePlayer[1].begin(2);
// NotePlayer[2].begin(6);
// NotePlayer[3].begin(45);
(serLCD is connected to TX pin 18)
if I enable the last two, the whole thing goes dead. No LCD, no nothing. If I leave them off, it works, and I get some response from the two enabled pins. Is this the limit? I keep reading about 6 available voices and how to avoid timer conflicts; am I just hitting a wall? I ultimately want to route the audio signals to analog filters controlled by SPI potentiometers, and wonder what pitfalls await me should I ever get that far.
Code includes much kludge, I just want the voices out so I can work on the analog electronics and polish it once it sings.
/*
TONETOY_0000
*/
#include <SoftwareSerial.h>
#include <serLCD.h>
#include <SPI.h>
#include <Tone.h>
//spi slave select
const int slaveSelectPin = 53;
//Declare scale
//number of voices
//pin 31 is select button
int selectButton = 31;
int playButton = 30;
int PlayNote;
int numVoices = 4;
//declare tone array!
Tone NotePlayer[4];
int menuUpdate = 100;
long menuRefresh = millis();
#define scaleC 0
#define scaleC# 1
#define scaleD 2
#define scaleD# 3
#define scaleE 4
#define scaleF 5
#define scaleF# 6
#define scaleG 7
#define scaleG# 8
#define scaleA 9
#define scaleA# 10
#define scaleB 11
// Set pin to the LCD's rxPin
int pin = 18;
serLCD lcd(pin);
// main menu string 10 options
int menuOptions = 10;
int Mode = 0;
int Key = 1;
int Top = 2;
int Bottom = 3;
int Length = 4;
int Odds = 5;
int Attack = 6;
int Decay = 7;
int Sustain = 8;
int Release = 9;
char* menuString[]={"Mode ", "Key ", "Top ", "Bottom ", "Length ",
"Odds ", "Attack ","Decay ","Sustain ","Release "};
//mode menu 33 modes
char* modeString[]={
"Major ",
"Minor ",
"Adonai ",
"Algerian ",
"Altered ",
"Augmented ",
"Blues ",
"Chromatic ",
"Arabic ",
"Enigmatic ",
"HalfDim ",
"Bebop ",
"HarmMaj ",
"HarmMin ",
"Hirajoshi ",
"HuGypsy ",
"HuMinor ",
"Insen ",
"Iwato ",
"Locrian ",
"Lydian ",
"Hemitonic ",
"Mixolydian ",
"NeaMajor ",
"NeaMinor ",
"Octatonic ",
"Persian ",
"Phrygian ",
"Prometheus ",
"Slendro ",
"Tritone ",
"UkrDorian ",
"WholeTone "
};
//Keys submenu 12 keys
char* keyString[]={"C ", "CS ", "D ", "DS ", "E ", "F ", "FS ", "G ", "GS ", "A ", "AS ", "B " };
//main parameter holder array
int settingsGrid[4][10] = {
{random(33), random(12), (random(4)+4), random(4), random(1023),random(256), random(256),random(256),random(256),random(256)},
{random(33), random(12), (random(4)+4), random(4), random(1023),random(256), random(256),random(256),random(256),random(256)},
{random(33), random(12), (random(4)+4), random(4), random(1023),random(256), random(256),random(256),random(256),random(256)},
{random(33), random(12), (random(4)+4), random(4), random(1023),random(256), random(256),random(256),random(256),random(256)},
};
//mode codes
int modeCode[] = {
2773,
2906,
3670,
2937,
3498,
2457,
2418,
4095,
3289,
3243,
2922,
3449,
2777,
2905,
3170,
2875,
2873,
3162,
2840,
3434,
2742,
3352,
2774,
3413,
3417,
3510,
3305,
3290,
2726,
2642,
3250,
2869,
2730
};
//key offsets
int keyOffset[]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
//NOTES
int Notes[] = {
NOTE_B0,
NOTE_C1,
NOTE_CS1,
NOTE_D1,
NOTE_DS1,
NOTE_E1,
NOTE_F1,
NOTE_FS1,
NOTE_G1,
NOTE_GS1,
NOTE_A1,
NOTE_AS1,
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2,
NOTE_C3,
NOTE_CS3,
NOTE_D3,
NOTE_DS3,
NOTE_E3,
NOTE_F3,
NOTE_FS3,
NOTE_G3,
NOTE_GS3,
NOTE_A3,
NOTE_AS3,
NOTE_B3,
NOTE_C4,
NOTE_CS4,
NOTE_D4,
NOTE_DS4,
NOTE_E4,
NOTE_F4,
NOTE_FS4,
NOTE_G4,
NOTE_GS4,
NOTE_A4,
NOTE_AS4,
NOTE_B4,
NOTE_C5,
NOTE_CS5,
NOTE_D5,
NOTE_DS5,
NOTE_E5,
NOTE_F5,
NOTE_FS5,
NOTE_G5,
NOTE_GS5,
NOTE_A5,
NOTE_AS5,
NOTE_B5,
NOTE_C6,
NOTE_CS6,
NOTE_D6,
NOTE_DS6,
NOTE_E6,
NOTE_F6,
NOTE_FS6,
NOTE_G6,
NOTE_GS6,
NOTE_A6,
NOTE_AS6,
NOTE_B6,
NOTE_C7,
NOTE_CS7,
NOTE_D7,
NOTE_DS7,
NOTE_E7,
NOTE_F7,
NOTE_FS7,
NOTE_G7,
NOTE_GS7,
NOTE_A7,
NOTE_AS7,
NOTE_B7,
NOTE_C8,
NOTE_CS8,
NOTE_D8,
NOTE_DS8
};
//timing stuff
long lastTime[4] = {0,0,0,0};
void setup()
{
NotePlayer[0].begin(9);
NotePlayer[1].begin(2);
// NotePlayer[2].begin(6);
// NotePlayer[3].begin(45);
pinMode(playButton, INPUT);
pinMode(selectButton, INPUT);
lcd.clear();
//slave select spi
pinMode (slaveSelectPin, OUTPUT);
// initialize SPI:
SPI.begin();
}
void loop()
{
if( (long)( millis() - (menuRefresh)+menuUpdate ) >= 0)
menuRefresh = millis();
lcd.setCursor(1, 1);
lcd.print("Voice");
lcd.setCursor(1, 8);
int voice = (analogRead(1)/256);
lcd.print((voice+1));
lcd.setCursor(2,1);
int pointer = (analogRead(2)/103);
lcd.print(menuString[pointer]);
if (pointer == 0)
{
lcd.print(modeString[settingsGrid[voice][pointer]]);
};
if (pointer == 1)
{
lcd.print(keyString[settingsGrid[voice][pointer]]);
}
if (pointer >= 2)
{
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
};
//ENTER DATA
while (digitalRead(selectButton) == HIGH)
{
switch (pointer)
{
case 0:
settingsGrid[voice][pointer] = (analogRead(2)/31.5);
lcd.setCursor(2,6);
lcd.print(modeString[settingsGrid[voice][pointer]]);
break;
case 1:
settingsGrid[voice][pointer] = (analogRead(2)/86);
lcd.setCursor(2,9);
lcd.print(keyString[settingsGrid[voice][pointer]]);
break;
case 2:
settingsGrid[voice][pointer] = (analogRead(2)/128);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 3:
settingsGrid[voice][pointer] = (analogRead(2)/128);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 4:
settingsGrid[voice][pointer] = (((analogRead(2)/8)*10)+50);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 5:
settingsGrid[voice][pointer] = (analogRead(2)/4);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 6:
settingsGrid[voice][pointer] = (analogRead(2)/4);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 7:
settingsGrid[voice][pointer] = (analogRead(2)/4);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
break;
case 8:
settingsGrid[voice][pointer] = (analogRead(2)/4);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
case 9:
settingsGrid[voice][pointer] = (analogRead(2)/4);
lcd.setCursor(2,9);
lcd.print(settingsGrid[voice][pointer]);
lcd.print(" ");
}
}
//NOTE SELECT, PLAY, ADSR LOOP?
while (digitalRead(playButton) == HIGH)
{for (int CurrentVoice = 0; CurrentVoice <= numVoices; CurrentVoice++)
if( (long)( millis() - (lastTime[CurrentVoice])+settingsGrid[CurrentVoice][Length] ) >= 0)
if (random(256) > settingsGrid[CurrentVoice][Length])
{
int ModeSig = settingsGrid[CurrentVoice][Mode];
int SelectNote = random ((((settingsGrid[CurrentVoice][Top])-(settingsGrid[CurrentVoice][Bottom]))*12));
if ((bitRead(settingsGrid[CurrentVoice][Mode], SelectNote)) ==1)
{
PlayNote = (SelectNote + settingsGrid[CurrentVoice][Key] + settingsGrid[CurrentVoice][Bottom]);
}
if (PlayNote > (((settingsGrid[CurrentVoice][Top])-(settingsGrid[CurrentVoice][Bottom]))*12))
{
PlayNote = PlayNote - (((settingsGrid[CurrentVoice][Top])-(settingsGrid[CurrentVoice][Bottom]))*12);
}
// lcd.setCursor(1,1);
// lcd.print(PlayNote);
//NotePlayer[CurrentVoice].stop();
NotePlayer[CurrentVoice].play(Notes[PlayNote], settingsGrid[CurrentVoice][Length] );
}
}
}