Go Down

Topic: Pulsing a sound sample from Attiny85 (Read 8239 times) previous topic - next topic

Bo_Andysin

Currently I'm building a toy prop with an Attiny85 to play a small, compressed sound clip, using a similar programming function as this example, which uses some of the same programming as the Trinket audio player. . .

http://www.instructables.com/id/Working-Sonic-Screwdriver-Version-30/#step14

Of course, my project is using a different sound clip: a wav file that's been converted to code, but similar to the example above. My only concern is this: when I press the pushbutton to activate the sound clip, how can I program my Arduino's code to make the entire clip play for its duration once -- only once each time button is pressed? In the example project in the link, the sound plays continuously as long as the button is held down, whereas in my idea, I'd like to have the button act like a trigger of a gun, which "blasts" the sound in its entirety each time the button is pressed. My sound clip is just a one-second laser noise, hence when compressed it could hopefully fit into the Attiny85, and of course I'm using my Arduino Uno as the bootloader. My programming knowledge is miniscule, hence I'm not sure how to adjust the Sonic Screwdriver code to pulse the sound rather than having it continuously stay on as long as the button is held down.

Thanks in advance!

Mr_arduino

#1
Jul 08, 2014, 04:05 am Last Edit: Jul 08, 2014, 04:15 am by Mr_arduino Reason: 1
You may be a little embarrassed when you see how simple it is but here are the changes you need to make
Step one right after
Code: [Select]

void setup() {

Add
Code: [Select]

cli(); /*Start with interupts disabled so that when we start setting up the audio the sound will not play */

Step two replace
Code: [Select]

void loop() {
delay(1000);
}

With
Code: [Select]

unsigned char isPlay;
void loop(){
if(buttonPressed()&&(!isPlay)){
fish=0;
isPlay=1;
sei(); /* Enable interupts so that the audio starts playing */
}
}

Step three replace buttonPressed with however you check if the button is pressed.
Step four replace
Code: [Select]

ISR(TIMER0_COMPA_vect) {
 OCR1B = pgm_read_byte(&sample[fish]);      // Read flash, write PWM reg.
 fish ++;
 if (fish >= sizesample){fish = 0;}
 /*
 if(++index >= samples) {           // End of audio data?
   index = 0;                       // We must repeat!
   flash.endRead();
   flash.beginRead(6);              // Skip 6 byte header
 }
 */
}

With
Code: [Select]

ISR(TIMER0_COMPA_vect){
OCR1B = pgm_read_byte(&sample[fish++]);      // Read flash, write PWM reg.
if (fish >= sizesample){
cli(); /* Disable interupts meaning that this function will not be called after the sample is finished playing */
isPlay=0;
}
}

I have not tested this code but it is highly likely to work.
I noticed that you were using the word fish for your sample counter although it is a bit funny doing this for more complex projects could increase maintenance difficulty. It is better to use descriptive variables. You don't need anything too long. Maybe something like sampCnt.
Also just one thing I noticed your code does not actually use any compression. You could easily do some forms of simple compression such as adpcm if you cannot fit your sound. Using adpcm would allow you to double or even quadruple the length of sound that you can fit in flash memory using the sample sample rate. And just one more thing I made it so that if the sound is playing and you press the button nothing will happen. If you remove the isPlay related stuff when you press the button it will restart the sound. It appears as though you want the sound to always complete so I implemented the extra check.

Bo_Andysin

@Mr._arduino -- thank you very much!!

I'm making the changes now and hopefully I'll test them in my breadboard later. I have another question, though: I've chosen a new sound clip -- a compressed 8000-sampled PCM wav that's around 7 KB, but when converted to code it becomes around 23 KB. The wav-to-code program I used doesn't support adpcm -- the program is Wusik WAV2Code, and only works with PCM. I tried wav2c, which didn't work right off the bat, and another wav-to-code program I tried output the text into a weird-looking format. Do you know of any open source freeware programs for converting compressed adpcm to code?

Thanks again in advance, and I'll let you know if this project works!

Mr_arduino

Well you get a text file right that contains a large array? If that is the case when you compile the program the compiler converts it back to data. Also I was thinking about coming up with my own converter I all of a sudden became interested in adpcm but I have no guarantees on when I will get to doing that.

Bo_Andysin

I was able to do some more tweaking, and I compressed the sound clip to about 6KB. I reckon that ought to fit on the Attiny85. Now that you mention it, I'd actually like to have the sound interrupt as opposed to playing in its entirety ; starting from where, which section exactly in the "isPlay" area needs to be removed?

Oh, another question: I'm not quite sure what you meant with step 3, about "replace buttonPressed with however you check if the button is pressed" -- is that in relation to the sound interrupting?

Thanks again!

-Bo

Mr_arduino

Do you want the sound to stop or start over if you press the button?
Also I did not know what pin the button is plugged into. I also did not know if when you press the button it becomes high or low.
Because I did not have this information I just put buttonPressed() as a placeholder.
It is your job to to replace this with proper code that checks if the button is pressed.

Bo_Andysin


Do you want the sound to stop or start over if you press the button?
Also I did not know what pin the button is plugged into. I also did not know if when you press the button it becomes high or low.
Because I did not have this information I just put buttonPressed() as a placeholder.
It is your job to to replace this with proper code that checks if the button is pressed.


I'd definitely like the sound to start again when the button is pressed -- like semi-automatic -- but one-shot-per-trigger-pull. If the button is pressed just once, it'll play the sound clip in its entirety (1 second noise), but if pressed in mid-sound burst, the sound will start again interrupting.

Also in the diagram from the Instructables page, the circuit doesn't exactly contain a schematic to illustrate where to add the connections of the Attiny -- but, instead there are photos that show the author's DIY circuit:

(starting from here, to the next steps about battery connectors, step 21) -- www.instructables.com/id/Working-Sonic-Screwdriver-Version-30/#step17

I'm assuming pin 1 and 8 would be jumped together, with the positive battery lead connecting to pins 1 and 8, the ground wire to pin 4, a capacitor's positive pin attached to pin 3, and the capacitor's ground pin attached to the speaker's positive wire. Then I'd connect the switch to the battery's positive wire that's attached to pins 1 and 8 again.

Mr_arduino

Ok to make the sound start from the beginning whenever you press the button remove the following
Code: [Select]

unsigned char isPlay;
&&(!isPlay)
isPlay=1;
isPlay=0;

Bo_Andysin

Thank you so much for your help! I'm going to test out my breadboard this weekend and do some experiments with sound, so in the meantime, here's my modified code which contains the repeating pulsing PCM, with interrupts - please let me know if this looks okay:

cjdelphi


Thank you so much for your help! I'm going to test out my breadboard this weekend and do some experiments with sound, so in the meantime, here's my modified code which contains the repeating pulsing PCM, with interrupts - please let me know if this looks okay:


Why not let yourself know if it works?

Mr_arduino

He will find out that it does not even compile.
There is no loop() and he has yet to remove
Code: [Select]

isPlay=0;

The loop is important to check when the button is pressed.

Bo_Andysin

#11
Jul 12, 2014, 09:12 pm Last Edit: Jul 12, 2014, 10:00 pm by Bo_Andysin Reason: 1

He will find out that it does not even compile.
There is no loop() and he has yet to remove
Code: [Select]

isPlay=0;

The loop is important to check when the button is pressed.


I'm actually running into some errors with testing the code:

When I add this. . .

Code: [Select]
unsigned char isPlay;
void loop(){
if(buttonPressed()&&(!isPlay)){
fish=0;
isPlay=1;
sei(); /* Enable interupts so that the audio starts playing */
}
}


I get an error message. I'm not sure what you originally meant by "replace buttonPressed with however you check if the button is pressed"; what particular variable should I specify?

Also, do I remove "isPlay=0" from the bottom of this:

Code: [Select]
ISR(TIMER0_COMPA_vect){
OCR1B = pgm_read_byte(&sample[fish++]);      // Read flash, write PWM reg.
if (fish >= sizesample){
cli(); /* Disable interupts meaning that this function will not be called after the sample is finished playing */
isPlay=0;
}
}


. . . Or do I have to specify a variable for "isPlay=0"? I'm not sure how to check for the loop.

Mr_arduino

#12
Jul 13, 2014, 06:19 am Last Edit: Jul 13, 2014, 06:21 am by Mr_arduino Reason: 1
You need to completely remove
isPlay=0; the whole line
Also remove
isPlay=1;
from the loop
Also write your own code to check if the button is pressed it is not that hard but I want you to do it. I am sure you are capable of figuring it out. I have already done more that I should have for code that you should be writing.

Go Up