Reading Multiple Files at Once Using GIGA R1

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);
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.