PaulRB:
For your 16 buzzers, will each have a fixed note, or will each be capable of playing any note at any time? How many buzzers will sound at the same time?
Each buzzer needs to be able to sound any note. At some points, all 16 buzzers will be playing different notes at one time.
Here's my attempt with micros(). The really important stuff is during the second to last function (Buzz) and the while loop within the main loop *I apologise if my syntax is wack:
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//SD STUFF
#define MILLIS_PER_BEAT 12 //Measured in midi units rather than usual music time signature
char fileName[] = "test.txt";
//this is taken from parseLinetest.ino
char delimiter[] = " "; //how each integer in the file is seperated
char* parsePosition; //ths is a "pointer" that directs the code to a position within the rawSdInput variable
int sdNoteInput[] = {0,0,0}; //the input of one line of instructions given by (time,channel, note or message) channel 0 is for messages
//these inputs have to be arrays because each character is read as a byte
unsigned long inputTime;
byte channel;
String input;
File myFile;
//LCD STUFF
#define BACKLIGHT_PIN 13
char lcdText;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
//BUZZER STUFF
#define NUMBER_OF_BUZZERS 16
const byte buzzer[] = {2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18}; //the digital pins of each buzzer
int buzzerFrequency[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //records the frequency that all buzzers are playing
long buzzerLastPeek[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //records the last time each buzzer switched between its LOW/High states
int buzzerState[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //records if the pin was last set high or low
#define NOTE_OFFSET -2 //needs to equal 10 +/- 12*(offset octaves)
//GENERAL STUFF
unsigned long loopStart; //the time the current loop started
unsigned long loopTime = 0; //the time during a loop (arbitrary to how many loops have occurred)
unsigned long microLoopTime = 0; //used for frequency calculations
unsigned long startTimer;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect.
}
Serial.print("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
// Switch on the backlight
pinMode ( BACKLIGHT_PIN, OUTPUT );
digitalWrite ( BACKLIGHT_PIN, HIGH );
lcd.begin(20,4); // initialize the lcd
lcd.setCursor(7,1); // go home (,Buddy. I work alone.)
lcd.print("START!");
//tone(2,262,500);
delay(1500);
lcd.clear();
//set all buzzer pins to output
for (byte i=0; i < NUMBER_OF_BUZZERS; i++){
pinMode(buzzer[i],OUTPUT);
digitalWrite(buzzer[i],LOW);
}
}
void loop(){
loopStart = millis();
//Open the file for reading:
myFile = SD.open(fileName);
if (myFile) {
Serial.println(fileName);
while (myFile.available()) {
microLoopTime = micros() - (loopStart*1000);
loopTime = microLoopTime/1000; //the current time is relative to the start time
if(1){ //WILL TEST IF IT IS A NOTE OR A MESSAGE
ReadNoteInput();
inputTime = sdNoteInput[0];
channel = sdNoteInput[1];
float freq = KeyToFrequency(sdNoteInput[2]);
/////////////////////////////////////////////////////////////////////////////this 'while' is looped for at least 12 milliseconds at a time
while (sdNoteInput[0] > loopTime/MILLIS_PER_BEAT){
microLoopTime = micros() - (loopStart*1000);
loopTime = microLoopTime/1000;
Buzz(microLoopTime); ///the buzz function is called
//Serial.println(micros()-startTimer);
//startTimer = micros();
}
/////////////////////////////////////////////////////////////////////////////end 'while'
lcd.clear();
lcd.setCursor(2,1);
lcd.print("Time: ");
lcd.setCursor(8,1);
lcd.print(loopTime);
lcd.setCursor(2,2);
lcd.print("Note: ");
lcd.setCursor(8,2);
lcd.print(buzzerFrequency[0]);
if (buzzerFrequency[channel-1] == freq){ //if this frequency is being played by this channel already, turn it off
buzzerFrequency[channel-1] = 0;
digitalWrite(buzzer[channel-1],LOW); //when off, the buzzer pin is set to low
} else{
buzzerFrequency[channel-1] = freq;
}
}
//THIS IS THE PART WHERE THEY BEEP AWAY
microLoopTime = micros() - (loopStart*1000);
Buzz(microLoopTime); //buzz the beepers with the input of the current time to compare to
for (byte j =1; j<4;j++){ //clear the recoded sd input
sdNoteInput[j] = 0;
}
}
}else{
Serial.println("couldn't open file");
while (1);
}
myFile.close(); //close the file
delay(1500);
}
void ReadNoteInput(){
String inputString = myFile.readStringUntil('\n'); //read the line and store it as a string
int stringLength = inputString.length();
char rawSdInput[stringLength+1];
inputString.toCharArray(rawSdInput,stringLength+1); //convert the string into char type of the same length as the string it is reading
parsePosition = strtok(rawSdInput, delimiter);
long value; //the value of the field of the array we are on
Serial.print("input array: ");
for (byte i=0;i<3;i++){ //repeat for each array field
value = atoi(parsePosition);
sdNoteInput[i] = value;
Serial.print(value);
Serial.print(", ");
parsePosition = strtok(NULL, delimiter); //move to next position. If we read a seperator don't store it as a value
}
Serial.println("");
}
void Buzz(long currentMicroTime){
for (byte i=0; i<3;i++){
//if this buzzer is set to be playing and the last time this buzzer switched states was longer than its frequency then switch its state
float nextBeep = buzzerLastPeek[i] + (buzzerFrequency[i] / 2); //this is when this buzzer should beep. the frequency is divided in half to find the high/low time of the wave
if ((buzzerFrequency[i] > 0) && (nextBeep < currentMicroTime)){
//switch the buzzer from whatever state it is currently in
if (buzzerState[i] < 0){
digitalWrite(buzzer[i],HIGH);
buzzerState[i] = 1;
} else {
digitalWrite(buzzer[i],LOW);
buzzerState[i] = -1;
}
buzzerLastPeek[channel-1] = microLoopTime; //log now as the time the buzzer compares to to time beeps
}
}
}
long KeyToFrequency(float key){
key += NOTE_OFFSET; //shift the note
key = double((key-49)/12);
Serial.print("key power: ");
Serial.println(key);
//this gives how many waves per second
float convertedFreq = double(pow(2,key))*440; //https://en.wikipedia.org/wiki/Piano_key_frequencies
//return how many microseconds between each wave
return double(1/convertedFreq)*1000000;
}
If you are curious, here's what the SD card txt file looks like:
0 1 60
100 2 70
120 1 60
200 2 70
500 16 65
540 14 53
600 16 65
600 14 53
Hopefully, this mess was of some help