Skip to content

SamdAudioSD Wiki Page

D34G edited this page Apr 18, 2021 · 8 revisions

Welcome to the SamdAudioSD wiki!

In the Player.ino file you will see an example that covers all relevant functions and procedures related to this library. The example sketch Player.ino and the library files SamdAudioSD.cpp and SamdAudioSD.h can be added to your Arduino IDE by downloading the zip files here and then by following this guide. I have built this library to be compatible with my Arudino Nano 33 IoT and it should be compatible with any Arduino that uses the SAMD21 chip. A list of Arduinos can be found here to identify if your board may be compatible with this library.

Here are some of the key aspects of this library. WAV files are read from an attached SD card using the SD.h library. Audio is then processed and sent out of a DAC pin to a connected Class D amplifier like the Adafruit PAM8302 or other amplifier of your choosing. Audio playback can be achieved through various methods. This library allows for non-blocking processing to allow for audio playback based on triggered events and when combined with the dynamic multi-channel feature layered audio is achievable for immersive or interactive projects. This library also allows for processing that blocks code execution until playback is complete for more linear needs in a project. Audio looping is possible and can be triggered to start or stop at any time when using non-blocking. Volume/gain control of an amplifier can be handled by this library and software volume control is possible when hardware control is not available. Also, temporary muting of audio is possible and can be triggered to start or stop at any time when using non-blocking.

Tutorial

The Player.ino file contains examples of all public functions contained in the SamdAudioSD library. Most functions are set to run either during setup or during the main loop based on commands sent from serial. The other functions are commented out but each function comes with a comment next to it to explain when it is appropriate or useful to use the function. In this tutorial I will break down each section of code from Player.ino to explain what it is and/or why you might use it.

Wiring diagram

[to be completed]

Libraries

Include these libraries at the top of your sketch:

#include <SPI.h>         // use this to communicate with spi devices 
#include <SamdAudioSD.h> // required to use this library 

Global Variables

Each of these variables are used throughout the example sketch. Modifiable variables for the SamdAudioSD library as well as Arduino pins are listed here for ease of use.

#define NUM_AUDIO_CHANNELS 4       // allows you to set the total number of playback channels
#define AUDIO_BUFFER_SIZE 512      // allows you to set the size of the audio processing buffer
#define YOUR_SD_CS 8               // the SPI chip select pin for your SD card reader
#define SHUTDOWN_PIN 7             // the shutdown pin for your amplifier, useful to conserve power and smooth out playback
#define DAC_PIN A0                 // the output pin for the audio signal which goes to the amplifier input
#define DIGITAL_POT 5              // the SPI chip select pin for your digital potentiometer, most amplifiers do not have this by default

SamdAudioSD AudioPlayer;           // this class object is your audio player, all commands will come in and out of this
const char *filename = "test.wav"; // the name of an example file to play from your SD card, be cautious of the 8.3 filename format*** and place in root of your sd card
uint32_t sampleRate = 44100;       // the sample rate of your 8-bit mono unsigned .WAV file

***note: be aware that if you are loading files onto the SD card using a computer with Windows, the filename may be truncated without your explicit knowledge. To avoid this make sure that your filenames are 8 characters or less and are followed with the three character extension (e.g. 1234test.wav). Check out this link if you want to understand more about this issue.

Setup

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
    delay(500);
  }

  Serial.print("Initializing SD card...");
  if (!SD.begin(YOUR_SD_CS)) // required to start communication with SD card
  {
    Serial.println(" failed!");
    return;
  }
  Serial.println(" done.");

  //SPI.setClockDivider(4); // hi-speed SPI transfers, needed if playing 88200khz sample rate (88200 currently not working, don't know why)
  AudioPlayer.selectShutdownPin(SHUTDOWN_PIN); // used to set shutdown pin (SD)** on amplifier if desired and set pinmode to output, if set .play() will power the amplifier up and down as needed
  AudioPlayer.selectDACPin(DAC_PIN); // used to set audio output pin on Arduino (defaults to pin A0)
  AudioPlayer.selectDigitalPotPin(DIGITAL_POT); // used to set the digital potentiometer*** pin on the arduino in order to control amplifier volume (note, if using other SPI devices all pins will have to be set high first)
  AudioPlayer.setVolume(100); // set the volume anywhere from 0 to 100 (note, if using other SPI devices all pins will have to be set high first)
  SPI.setClockDivider(12); // brings the SPI clock back to default, needed when using a digital potentiometer due to poor SPI usage in the MCP4XXX library
  //AudioPlayer.setBlocking(true); // code execution waits for audio to finish (default is set to false)*
  AudioPlayer.begin(sampleRate, NUM_AUDIO_CHANNELS, AUDIO_BUFFER_SIZE); // required inputs: sample rate, number of audio channels possible, size of audio buffer for processing

  Serial.print("Playing file: ");
  Serial.println(filename);
  AudioPlayer.play(filename); // plays audio on channel one only
  
  Serial.println("Send any command to continue...");
}

*note: If you require your code to use event based triggers for audio playback then uncomment or add the line 'setBlocking(true)' to your setup.
**note: If you are not using a Class D amplifier with the Shutdown Pin (SD) then comment out the lines of code related to 'selectShutdownPin(shutdownPin)' and 'setShutdownPinState(pinState)' to avoid unintended behavior.
***note: Also if you are not using a Class D amplifier or you are not using a digital potentiometer to control the amplifier's gain then comment out the lines of code in setup related to 'selectDigitalPotPin(digitalPot)' and 'setVolume(volume)' to avoid unintended behavior.

Loop

void loop()
{
  if (Serial.available()) {
    char c = Serial.read();

    if ( c == 'o') 
    {
      AudioPlayer.play("test1.wav", 0);  // plays audio on channel 1
      Serial.println("playing on ch1!");
    }
    else if ( c == 'O') 
    {
      AudioPlayer.play("test2.wav", 1);  // plays audio on channel 2
      Serial.println("playing on ch2!");
    }
    else if ( c == 's') 
    {
      AudioPlayer.play("test3.wav", 2);  // plays audio on channel 3
      Serial.println("playing on ch3!");
    }
    else if ( c == 'S') 
    {
      AudioPlayer.play("test4.wav", 3);  // plays audio on channel 4
      Serial.println("playing on ch4!");
    }
    else if ( c == 'l') 
    {
      AudioPlayer.loopChannel(0, true);  // sets flag to loop channel one as true to loop until flag is set false
      Serial.println("start looping ch1!"); 
    }
    else if ( c == 'L') 
    {
      AudioPlayer.loopChannel(0, false);  // removes flag to loop channel one to false to stop looping once current playback completes
      Serial.println("stop looping ch1!");
    }
    else if ( c == 'g') 
    {
      AudioPlayer.gainUp();  // a software control which increases volume during audio processing 
      Serial.println("increase gain!");
    }
    else if ( c == 'G') 
    {
      AudioPlayer.gainDown();   // a software control which decreases volume during audio processing 
      Serial.println("decrease gain!");
    }
    else if ( c == 'v') 
    {
      AudioPlayer.volumeUp();   // a hardware control which increases amplifier volume through use of a digital potentiometer like the MCP4151 or MCP 4152 (note, if using other SPI devices all pins will have to be set high first)
      Serial.println("increase volume!");
    }
    else if ( c == 'V') 
    {
      AudioPlayer.volumeDown();  // a hardware control which decreases amplifier volume through use of a digital potentiometer like the MCP4151 or MCP 4152 (note, if using other SPI devices all pins will have to be set high first)
      Serial.println("decrease volume!");
    }
    else if ( c == '0') 
    {
      AudioPlayer.stopChannel(0);  // stops playback on channel 1
      Serial.println("ch1 off!");
    }
    else if ( c == '1') 
    {
      AudioPlayer.stopChannel(1);  // stops playback on channel 2
      Serial.println("ch2 off!");
    }
    else if ( c == '2') 
    {
      AudioPlayer.stopChannel(2);  // stops playback on channel 3
      Serial.println("ch3 off!");
    }
    else if ( c == '3') 
    {
      AudioPlayer.stopChannel(3);  // stops playback on channel 4
      Serial.println("ch4 off!");
    }
    else if ( c == 'X') 
    {
      AudioPlayer.end();  // terminates audioplayer session
      Serial.println("stop audio player!");
    }
    else if ( c == 'Y') 
    {
      AudioPlayer.setShutdownPinState(LOW, true); // sets SD*** output pin LOW, to deactivate amplifier and set mute flag to prevent the SD pin going high during playback
      Serial.println("mute!");
    }
    else if ( c == 'y') 
    {
      AudioPlayer.setShutdownPinState(HIGH, false); // sets SD*** output pin HIGH, to activate amplifier and remove mute flag for the SD pin
      Serial.println("unmute!");
    }
  }

***note: If you are not using a Class D amplifier with the Shutdown Pin (SD) then comment out the lines of code related to 'selectShutdownPin(shutdownPin)' and 'setShutdownPinState(pinState)' to avoid unintended behavior.

A video and picture filled, fun fantastic tutorial is coming soon!

Useful Links

Arduino IoT Boards
SD Card Module
Class D Audio Amplifier - PAM8302
Speaker 8 Ohm 1 Watt

Examples for wiring SPI controlled digital potentiometers:
-- https://www.arduino.cc/en/Tutorial/LibraryExamples/DigitalPotControl
-- https://www.electroschematics.com/learn-use-digital-potentiometers/
-- http://www.learningaboutelectronics.com/Articles/MCP4131-digital-potentiometer-circuit.php
-- http://matthewcmcmillan.blogspot.com/2014/03/arduino-using-digital-potentiometers.html

Examples for wiring SPI controlled SD card:
-- https://alexlubbock.com/micro-sd-adapter-esp8266-esp32
-- https://www.reddit.com/r/AskElectronics/comments/ek1da3/how_to_properly_make_an_microsd_card_spi_circuit/
-- https://www.mischianti.org/2019/12/15/how-to-use-sd-card-with-esp8266-and-arduino/
-- https://www.sunrom.com/p/micro-sd-card-socket-push-in---pull-out
-- https://www.youtube.com/watch?v=qIbu01GlxmE -- https://forum.arduino.cc/index.php?topic=49649.msg354701#msg354701

Features

Plays Mono channel unsigned 8-bit mono .WAV files with sample rates of 22050 Hz, 32000 Hz, or 44100 Hz
Reading audio files from an SD card using SPI
Software volume control
Hardware volume control
Multi channel audio playback
Audio playback looping
Audio mute
Blocking and non-blocking audio playback
Audio playback status

Dependencies

MCP4XXX Library https://github.com/D34G/mcp4xxx (control of digital potentiometer circuits for amps with electronic control of gain)

Available Functions

    void begin(uint32_t sampleRate, uint8_t numOfChannels, uint16_t audio_buffer_size);
        // initates audio player. variables required are sample rate, number of channels to use, and audio buffer size

    void play(const char *fname, uint8_t channel);
        // to play a single track, used when multiple channels are necessary

    void play(const char *fname);
        // to play a single track, used when multiple channels are not necessary

    void stopChannel(uint8_t c);
        // called to stop a specific audio channel

    void loopChannel(uint8_t c, bool loopEnable);
        // sets a specific channel to be looped until stopped

    void setBlocking(bool blockFlag);
        // enable or disable blocking mode to prevent code execution play() until audio track finishes, disabled by default

    bool isPlaying(uint8_t c);
        // check to see if selected channel is playing

    void setGain(uint8_t v);
        // set initial volume, default set to 4 (shouldn't need if using hardware gain control)

    void gainUp();
        // increase volume (shouldn't need if using hardware gain control)

    void gainDown();
        // increase volume (shouldn't need if using hardware gain control)

    void setVolume(uint8_t v);
       // move the wiper of the digital potentiometer to the selected value from 0 to 100 (scaled to 0-255) (note, if using other SPI devices all pins will have to be set high first)

    void volumeUp();
        // decrement the wiper of the digital potentiometer by one (note, if using other SPI devices all pins will have to be set high first)

    void volumeDown();
        // increment the wiper of the digital potentiometer by one (note, if using other SPI devices all pins will have to be set high first)

    void end();
        // called to manually stop the audio player

    void selectShutdownPin(uint8_t shutdownPin);
        // select the pin to control amplifiers that contain shutdown pins (SD)

    void setShutdownPinState(bool pinState);
        // change the state of the shutdown pin of an amplifier

    void setShutdownPinState(bool pinState, bool muteAudio);
        // change the state of the shutdown pin of an amplifier while setting mute flag

    void selectDACPin(uint8_t audioOutputPin);
        // select the audio output pin on the microcontroller4

    void selectDigitalPotPin(uint8_t DigitalPotPin);
        // select the digital potentiometer pin on the microcontroller

Let me know if you liked my library or if you'd like to contribute!