Hi, I am using a GIGA R1 to try and create a functional piano keyboard. Currently, the Arduino is reading files stored on a USB which correspond to each button in the keyboard, and the output comes through the DAC.
An issue I have come across is playing chords, I need to try and figure out a way to allow the Arduino to output multiple notes at once.
Does anyone have any advice for this? I will attach my current code here.
I am not very experienced with programming, so I apologise if I am missing an easy fix.
#include <Arduino_AdvancedAnalog.h>
#include <Arduino_USBHostMbed5.h>
#include <FATFileSystem.h>
// Define Button Pins
#define C_BUTTON 22
#define BUTTON 23
AdvancedDAC dac1(A12);
USBHostMSD msd;
mbed::FATFileSystem usb("USB_DRIVE");
FILE *file_c = nullptr; // File for C_BUTTON
FILE *file_b = nullptr; // File for BUTTON
int sample_size_c = 0;
int sample_size_b = 0;
void setup()
{
Serial.begin(115200);
while (!Serial);
/* Enable power for HOST USB connector. */
pinMode(PA_15, OUTPUT);
digitalWrite(PA_15, HIGH);
pinMode(C_BUTTON, INPUT_PULLUP); // Assuming the button is connected with a pull-up resistor
pinMode(BUTTON, INPUT_PULLUP); // Assuming the button is connected with a pull-up resistor
Serial.println("Please connect a USB stick to the GIGA's USB port ...");
while (!msd.connect())
delay(100);
Serial.println("Mounting USB device ...");
int const rc_mount = usb.mount(&msd);
if (rc_mount)
{
Serial.print("Error mounting USB device ");
Serial.println(rc_mount);
return;
}
Serial.println("Opening audio files ...");
// Open audio file for C_BUTTON
file_c = fopen("/USB_DRIVE/Untitled.wav", "rb");
if (file_c == nullptr)
{
Serial.print("Error opening audio file for C_BUTTON: ");
Serial.println(strerror(errno));
return;
}
// Open audio file for BUTTON
file_b = fopen("/USB_DRIVE/AUDIO_SAMPLE.wav", "rb");
if (file_b == nullptr)
{
Serial.print("Error opening audio file for BUTTON: ");
Serial.println(strerror(errno));
return;
}
// Read audio header for C_BUTTON file
// Assuming the audio file format is the same for both files
struct wav_header_t
{
char chunkID[4]; //"RIFF" = 0x46464952
unsigned long chunkSize; //28 [+ sizeof(wExtraFormatBytes) + wExtraFormatBytes] + sum(sizeof(chunk.id) + sizeof(chunk.size) + chunk.size)
char format[4]; //"WAVE" = 0x45564157
char subchunk1ID[4]; //"fmt " = 0x20746D66
unsigned long subchunk1Size; //16 [+ sizeof(wExtraFormatBytes) + wExtraFormatBytes]
unsigned short audioFormat;
unsigned short numChannels;
unsigned long sampleRate;
unsigned long byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
};
wav_header_t header;
fread(&header, sizeof(header), 1, file_c);
sample_size_c = header.bitsPerSample / 8; // Determine sample size for C_BUTTON
// Read audio header for BUTTON file
fread(&header, sizeof(header), 1, file_b);
sample_size_b = header.bitsPerSample / 8; // Determine sample size for BUTTON
// Configure the advanced DAC
if (!dac1.begin(AN_RESOLUTION_12, header.sampleRate, 256, 16))
{
Serial.println("Failed to start DAC1 !");
return;
}
}
void loop()
{
// Read the state of the buttons
int buttonStateC = digitalRead(C_BUTTON);
int buttonStateB = digitalRead(BUTTON);
// Clear the serial monitor
Serial.print("\033[2J\033[H");
// Print the current button states
Serial.print("Button C State: ");
Serial.println(buttonStateC);
Serial.print("Button B State: ");
Serial.println(buttonStateB);
// Check if the C button state is HIGH (button is pressed)
if (buttonStateC == HIGH)
{
// If the C button is pressed, play the audio file
if (dac1.available() && !feof(file_c))
{
// Read data from file
uint16_t sample_data[256] = {0};
fread(sample_data, sample_size_c, 256, file_c);
// Get a free buffer for writing
SampleBuffer buf = dac1.dequeue();
// Volume control factor (0.0 to 1.0)
float volume = 0.3; // Example: Reduce volume to 50%
// Write data to buffer
for (size_t i = 0; i < buf.size(); i++)
{
// Scale down to 12 bit and apply volume control
uint16_t const dac_val = ((static_cast<unsigned int>(sample_data[i]) + 32768) >> 4) & 0x0FFF;
uint16_t volume_adjusted_val = static_cast<uint16_t>(dac_val * volume) & 0x0FFF;
buf[i] = volume_adjusted_val;
}
// Write the buffer to DAC
dac1.write(buf);
}
}
else
{
// If the C button is not pressed, stop playing the audio by resetting the file pointer
fseek(file_c, 0, SEEK_SET);
}
// Check if the B button state is HIGH (button is pressed)
if (buttonStateB == HIGH)
{
// If the B button is pressed, play the audio file
if (dac1.available() && !feof(file_b))
{
// Read data from file
uint16_t sample_data[256] = {0};
fread(sample_data, sample_size_b, 256, file_b);
// Get a free buffer for writing
SampleBuffer buf = dac1.dequeue();
// Volume control factor (0.0 to 1.0)
float volume = 0.3; // Example: Reduce volume to 50%
// Write data to buffer
for (size_t i = 0; i < buf.size(); i++)
{
// Scale down to 12 bit and apply volume control
uint16_t const dac_val = ((static_cast<unsigned int>(sample_data[i]) + 32768) >> 4) & 0x0FFF;
uint16_t volume_adjusted_val = static_cast<uint16_t>(dac_val * volume) & 0x0FFF;
buf[i] = volume_adjusted_val;
}
// Write the buffer to DAC
dac1.write(buf);
}
}
else
{
// If the B button is not pressed, stop playing the audio by resetting the file pointer
fseek(file_b, 0, SEEK_SET);
}
}