Instantiating AudioPlaySdWav from a library.

Status
Not open for further replies.

Gronnesby

Member
Hi!
I've been trying to write a library for a teensy-based project I'm doing.
In the library I instantiate 6 AudioPlaySdWav objects to connect to a mixer,
this is so that I can play multiple audio streams on top of eachother.

When I try to instantiate the 6 objects, the constructor AudioPlaySdWav()
seems to halt. The AudioPlaySdWav() is instantiated within a init() method
of the class in the library (not the constructor):

Code:
    Serial.println("Setting up Audio Channels");
    _N_CHANNELS = 6;
    for (int i = 0; i < _N_CHANNELS; i++)
    {
        Serial.print("Setting up channel ");
        Serial.println(i);
        _CHANNELS[i] = AudioPlaySdWav(); // Stops here for some reason
        Serial.println("Connecting channel to mixer");
        AudioConnection(_CHANNELS[i], 0, _MIXER, i);
    }

It does not go past the first two prints.
Any ideas what might be causing it?

I am running this on a teensy 3.5, using the builtin SD card as the source (which is not initialized yet).
Everything is compiled through the Arduino IDE (gave up trying to compile everything by hand).
The Audio version is 1.3.

Thanks!
 
My first guess is you're creating the new AudioConnection as a local variable. Each time the loop ends, the one you just created goes out of scope and its destructor is called.

But the audio lib doesn't allow AudioConnection to ever be destroyed. If you do, other parts of the library will retain references to them, and then the whole thing crashes when it tries to use the memory that's no longer an AudioConnection object!

You need to create these as static variables, or (maybe) create them on the heap with C++ new.


And yeah, the way things generally work here is we expect a complete program which can be copied into Arduino and actually run to reproduce the problem. Please try to post complete code in your messages. Even if it seems unnecessary, often it turns out to be the key to really figuring out what's wrong.
 
The code is incomplete. How did you declare _CHANNELS ?
It is probably easier if I just post the whole code. But now that you mention it, _CHANNELS probably cannot be statically allocated as a private member of the class.
I've mostly worked with C before, where it would make sense to declare first and then assign stuff to it later.
Anyway, to confirm my suspicion, here is the code:
header (AudioSystem.h) file:
Code:
#include <Audio.h>
#include <SD.h>
#include <SPI.h>


class AudioSystem
{
    private:
        uint8_t _N_CHANNELS = 6; // I've put this here for now
        uint8_t _CURRENT_CHANNEL = 0;
        const uint8_t _SDCARD_MOSI_PIN = 11;
        const uint8_t _SDCARD_SCK_PIN = 13;
        const uint8_t _SDCARD_CS_PIN = BUILTIN_SDCARD;
        AudioPlaySdWav _CHANNELS[6];
        AudioMixer4 _MIXER;

    public:
        AudioSystem()
        {
        }
        ~AudioSystem()
        {
        }

        void init();
        void playSound(char *soundType);
};

And the source (AudioSystem.cpp) file:

Code:
#include "AudioSystem.h"

void AudioSystem::init()
{
    Serial.println("Allocating Memory");
    AudioMemory(20);
    Serial.println("Done");
    Serial.println("Setting up Audio Channels");
    
    for (int i = 0; i < _N_CHANNELS; i++)
    {
        Serial.print("Setting up channel ");
        Serial.println(i);
        _CHANNELS[i] = AudioPlaySdWav(); // This is were the crash occurs, it probably needs to be dynamically allocated?
        Serial.println("Connecting channel to mixer");
        AudioConnection(_CHANNELS[i], 0, _MIXER, i);
    }
    Serial.println("Done");
    Serial.println("Connecting Mixer and DAC");
    AudioOutputAnalogStereo dac;
    AudioConnection conn(_MIXER, 0, dac, 1);

    
    Serial.println("Starting Channels, adjusting gain");
    for (int i = 0; i < _N_CHANNELS; i++)
    {
        _CHANNELS[i].begin();
        _MIXER.gain(i, 0.4);
    }
    Serial.println("Done");
    Serial.println("Initializing SD");
    SPI.setMOSI(_SDCARD_MOSI_PIN);
    SPI.setSCK(_SDCARD_SCK_PIN);
    if (!SD.begin(_SDCARD_CS_PIN))
    {
        while(1)
        {
            Serial.println("Unable to access SD card");
            delay(200);
        }
        
    }

    Serial.println("Done");

}

void AudioSystem::playSound(char *soundType)
{
}

Also, in reference to Paul's answer, I will probably need to save the other objects (AudioConnection, AudioOutputAnalogStereo) as well (though the program seem to crash before they are ever made in this function).

EDIT: Oh, and the .ino file I use with it:
Code:
#include <AudioSystem.h>

AudioSystem AS;

void setup()
{
    Serial.begin(9600);
    AS.init();
}

void loop()
{

}
 
Last edited:
though the program seem to crash before they are ever made in this function

Keep in mind Serial.print() packs data into USB buffers. They actually get sent later, due to USB interrupts or timeouts. If your code causes the ARM processor to hard fault, the text your printed will remain in those buffers and never appear at your PC.

The default fault handers try to detect if any USB data was setting around, and they try to send it without depending on interrupts. But certain types of crashes can't do anything, especially if things go very wrong and overwrite critical locations in memory.

Use Serial.send_now() and/or a delay of several milliseconds after printing to make sure it actually gets out of the Teensy and into your PC, before you move on to execute code that might crash badly.
 
Status
Not open for further replies.
Back
Top