odd Audio Library mixer.gain behaviour.

Status
Not open for further replies.

Cosford

Well-known member
Hi guys,

Working on something at the moment with two audio channels being fed into a mixer. One is background music, one is an announcement or sound effect.
These two channels are mixed in a mixer4 and output via the T3.1 DAC.

My audio objects are defined as follows:

Code:
AudioPlaySdWav		sound_player;
AudioPlaySdWav		music_player;
AudioOutputAnalog	dac;
AudioMixer4			mixer;
AudioConnection		sound_to_mixer(sound_player, 0, mixer, 0);
AudioConnection		music_to_mixer(music_player, 0, mixer, 1);
AudioConnection		mixer_to_output(mixer, 0, dac, 0);

Initialisation:

Code:
	AudioMemory(10);
	dac.analogReference(INTERNAL);
	mixer.gain(0, 1.0);
	mixer.gain(1, 1.0);
	if (SD.begin(6))			//Hardcoded!
		audioInitialised = true;
	else
		audioInitialised = false;

Now, the structure of my 'play' functions is:

Code:
void playSound() {
	sound_player.play("test.wav");
	if (music_player.isPlaying())
		mixer.gain(1, 0.1);		//quiet music volume if sound effect is playing.
}

My loop function looks like this:

Code:
elapsedMillis timer = 0;

void loop() {
//do some unrelated stuff.
	if (!(sound_player.isPlaying())) {
		mixer.gain(1, 1.0);
		Serial.println("Not playing!");
	}
	else Serial.println("Playing");
if(timer > 5000) {
timer = 0;
playSound();
}


Now, the behaviour I'm getting, is that the volume of channel 1 of the mixer (music) is never returned to 1.0, despite isPlaying() working as intended. (Note the Serial.println() calls to verify this).

However, adding a small delay to the end of the loop seems to resolve it.
EG

Code:
elapsedMillis timer = 0;

void loop() {
//do some unrelated stuff.
	if (!(sound_player.isPlaying())) {
		mixer.gain(1, 1.0);
		Serial.println("Not playing!");
	}
	else Serial.println("Playing");
if(timer > 5000) {
timer = 0;
playSound();
}

delay(50);

Any ideas? Sorry this wasn't very clear; struggling to understand it myself, let alone explain it. Of course, I'm aware that I'm asking it to continuously update the gain of the channel (unnecessarily 90% of the time) and that there are likely better ways of doing this, but it just seems odd?
 
Last edited:
On further investigation, it seems that my issue may be caused by (isPlaying()) returning false, immediately upon starting to play a track. I guess I need to allow an interrupt to happen and update the isPlaying() function before calling it?

Any ideas how I can prevent isPlaying() being called and read before it's had a chance to be updated, without using a delay()?

EDIT: Eventually solved by using a couple of booleans.

Code:
bool soundStarted = false;
bool soundPlaying = false;

Code:
if(soundStarted && sound_player.isPlaying()) {    //Make sure we're actually playing.
soundPlaying = true;
soundStarted = false;
}

if(soundPlaying && !sound_player.isPlaying()) {   //Now we're sure that we WERE playing, we can be sure we've actually stopped.
//correct our volumes.
}
 
Last edited:
Any ideas how I can prevent isPlaying() being called and read before it's had a chance to be updated, without using a delay()?

Unfortunately, you can't. It's a fundamental problem with the way the SD player is currently implemented, where it parses the WAV header inside the audio update.

I probably will redesign the player object someday. But before I even think about that, the SD library rewrite needs to move from experimental read-only to actually replacing the limited SD library we have today. So much more will become possible once we have a proper caching, thread-safe SD library.
 
Status
Not open for further replies.
Back
Top