Pages: [1]   Go Down
Author Topic: First read OK, after that reads distorted  (Read 1822 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

I am working on creating a simple electronic drum kit using an Arduino Due microcontroller.  I currently have piezo sensors detecting a hit, and am able to have audio playback through headphones.  I am storing the audio samples on an SD card, and using SPI to interface an adafruit SD shield.

After resetting the board, I can hit a sensor and play back a sound sample through the DAC loud and clear.  My problem is that if I hit the sensor a second, third, fourth time etc...samples are played very distorted.  I am wondering why the first sample plays so clearly, but the following samples are so unclear. 

I've also noticed that after resetting the board, I hear absolutely nothing through the headphones.  After hitting a sensor once, it plays, and when it is complete some static sound remains. 

I've attached a text file with my code, as well as a picture of the project (nything left of the pot is an amplifier circuit that is only used for speaker playback, not the headphones).

If anybody has an experience using SD over SPI for audio playback, any insight into this issue is greatly appreciated.

Thanks,
Greg


* IMG_20130318_112928.jpg (1547.54 KB, 2560x1920 - viewed 29 times.)
* SD_Audio_Code.txt (5.19 KB - downloaded 14 times.)
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What library is audio.h? Is it included in Arduino DUE? I wonder if you should be calling audio.prepare() after reading each byte from the file or calling it once with all the bytes from the file.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah, Audio.H is included with the Arduino Due, for use with the onboard DAC's.  I referenced the Arduino Audio library on the Arduino website

http://arduino.cc/en/Reference/Audio

I will have a look through the code tonight and see if I can expand on your ideas.

Thanks,
Greg
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK. I read the DUE reference on arduino site after reading your post. It seems you are doing everything the same as they were doing it in their sample code. You read in a block of data, play it, read more, play more, until there's nothing to play.

Just to clarify, regardless which sound you play after a reset, the first round is always smooth and the second round and beyond are always distorted?
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, I am not the strongest programmer so I tried to use the arduino reference as a template for my code.  You're also correct regarding the distortion.  I have two sound samples setup at the moment, a snare drum, and little 15 second drum sample.  Both will play well, if played first after a reset.  Regardless of which is pressed second, it will be distorted.

You mention that I am reading and playing blocks at a time, is this in block sizes of the buffer?
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, your buffer size is 1024. What about doing audio.begin() before you open file and play? Remove the begin from setup and move it before this line in each audio:

File myFile = SD.open("test.wav");

In the ONLY sample code given on arduino official site, the program just hangs at the end of the playback (with a dead while loop), not repeated playbacks. This is just another example of a library can only .begin() and no .end() functions. That seems to be the arduino style smiley-wink
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Some interesting results, from doing what you had suggested above.

The first, and second times I play the file are now working great. At first, I thought you had solved the problem. However, it will simply not even play a third time.  It starts to play, and cuts out almost immediately.  A fourth, fifth attempt etc, nothing will happen if I hit any of the inputs.  The board "tx" led lights up, so its acknowledging my input, but the SD card shows no activity.

I have some simple text output that runs in the serial monitor to show when sounds are being played, and some basic init stuff.  This picture helps explain what I'm seeing.  The first two samples "Playing..." work great.  The third seems to hang here.



* ThirdSampleHang.png (245.86 KB, 1366x768 - viewed 22 times.)
« Last Edit: March 20, 2013, 06:36:35 pm by kopi » Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I wish they have an end(0 method so you can properly end the audio play and start it again for a new file. Any progress?
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Unfortunately, not.

By moving the Audio.Begin line into each IF statement, I get 2 great sounding playbacks, and on button press the code locks up at "playing...."

By moving the Audio.Begin line out of each IF statement, and only declaring once during initialization, I get 1 great sounding playback, followed by a distorted sound on any more button presses.

I've been struggling trying to re-write my code but as far as I can tell this is the only way I know how to do it smiley-sad

I feel like since initialization and setup seems to provide a functional playback, that my problem must be in how it is buffering the sample.  I've been trying different buffer sizes but so far it has only led to different sounding distortion in playback.
« Last Edit: April 01, 2013, 03:34:22 pm by kopi » Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

There's nothing you can do. The audio provides no end(). If I were to play an audio I would do begin, than prepare and then play and then end so I can start over. These Arduino guys don't always provide end methods. Post on DUE board to see if you get more attention. FYI, the Serial used to have no end() method.
Logged


UK
Offline Offline
Newbie
*
Karma: 1
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was having the exact same problem.

There is actually an end() function in the library. It just doesn't seem to be documented! ( This is in arduino 1.5.2 )
This can be seen in hardware/arduino/sam/libraries/Audio/audio.cpp + audio.h

void AudioClass::end() {
   dac->end();
   free( buffer);
}

As you can see it closes down the DAC's and frees the buffer. So you can call begin() again safely. If no end is called the buffer is not freed and after a few calls the units memory fills up and crashes the arduino, as you have seen. This should solve your problem.

However I found this caused a rather annoying 'popping' sound as the DAC's were switched on and off after each bit of audio. Really annoying if you want clean audio!
I found a way round this by adding my own function in:

In audio.h I added a construct for my own function.

public:

void reset();

In audio.cpp under the begin() function I altered the malloc call to a calloc call - to ensure the buffer was filled with zero's

buffer = (uint32_t *) calloc(bufferSize, sizeof(uint32_t));


The reset function is pretty much a replica of the begin function, but without the DAC initialisations, and an all important call to free the old buffer. bufferSize has already been calculated in the begin() call so we don't need to do that again.

void AudioClass::reset() {
   free( buffer );
   
   // Allocate a buffer to keep msPreBuffer milliseconds of audio
   buffer = (uint32_t *) calloc(bufferSize, sizeof(uint32_t));
   half = buffer + bufferSize / 2;
   last = buffer + bufferSize;

   // Buffering starts from the beginning
   running = buffer;
   next = buffer;
}

Once your audio clip has finished playing you can now just call Audio.reset() and this will clear the buffer for the next bit of audio without turning the DAC's off.

If your audio files have different sample rates you will have to call end() then begin() again as the DAC's are parsed the sample rates when initialised.

I am sure this is not a the perfect fix, and there are likely better ways to get round this. But it worked for me.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 72
Posts: 7175
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

mekuni,

Thanks for sharing! I wish Arduino team will read this post and make some changes to their code smiley I'm sure this will help the OP +karma for you
Logged


Pages: [1]   Go Up
Jump to: