ATTiny and wav player

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

I have a copy of mr Chan's wav player, i want to change it to include some things i want to do, the first problem is when i compiled it it threw some errors, so are the files diskio.h interger.h main.c mmc.c pff.cpff.h and xitoa.h all the files for the player?, i noticed he pulled some avr files, but they are not in his folders!. Secondly when i get the program to run, how do i convert it to hex?, thirdly the avrdudegui program is the program to write the hex to the attiny85?

thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which compiler did you use? There are several avr c compilers, slight differences between them.

 

Imagecraft compiler user

Last Edited: Sat. May 7, 2016 - 03:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chan writes for avr-gcc. The errors are most likely the Chang at 4.6 that insists that flash data must be "const". The solution, if it's that, is to add "const" (just like the error message tells you). The output of an avr-gcc build will be a .hex file. 

Last Edited: Sat. May 7, 2016 - 03:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I have to download, install use an AVR compiler? as at the moment i am using the arduino program!?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, i looked through the code and wanted to edit it, but, the "speakerpin" has no allocation of an actual number to it!, it is just declared!, nor are any of the other pins!, so how does it pick up the pin numbers?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Um. That's because it's a C program and you have a C++ compiler.

 

Perhaps you can show us the first error line and somebody can tell you how to fix it. Or maybe just where to get a C compiler.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So the Big Picture seems to be: how to port the ansi c chan wavplayer to the Arduino ide? Or is the goal to just compile and use the chan waveplayer? Seems like downloading the free atmelstudio 7, which is the ide for the gnu avr c and c++ compiler would allow someone to create a project, add the chan c files to the project, hit the compile button? No money spent yet.

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so i see that i need a c compiler, i attempted to download and install atmel studio 7 but when it starts it stops immediately and i get a windows window saying "this app can't run on your computer", and i am running Windows 10!, i attempted to search for info, but none available, i attempted to run it in windows 7/8 compatibility with no luck!

thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Theone6000 wrote:

Ok, so i see that i need a c compiler, i attempted to download and install atmel studio 7 but when it starts it stops immediately and i get a windows window saying "this app can't run on your computer", and i am running Windows 10!, i attempted to search for info, but none available, i attempted to run it in windows 7/8 compatibility with no luck!

thanks!

 

Well that's curious. I use Studio 7 on my 64 bit Windows 10 computer. You got the big download? It's like a gigabyte. 

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I downloaded the internet install, and it didn't work, then the offline install and it didn't work, and then deleted the files and did a fresh download of the internet install, and when i went to install it came up with the "reboot needed" from the studio program, so rebooted, and started the install and it is currently installing!. It seems to be about a gig and takes a while, i have a ssd sitting next to me that along with a graphics card that i intend to install, so the download files can be transferred to the new drive, or does a new install/download have to be done?

 

as for chen's program, i cut a lot of the option stuff that isn't needed out, and have pretty well got the core, just a few questions, the "metadata" thing isn't needed to just play wav files?, and it doesn't list the attiny85 as an option for the register code, so what mega does the attiny85 use the same registers of?

thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so a burst of good news!, i downloaded and started install of atmel studio 7 last night, but it crashed, this morning it started again, then window decided it had to do an install and refresh, but eventually Atmel studio 7 finished, and works!, woohoo!. I also figured out what was needed and what wasn't in the Chen code, and have it currently down to about 6kb (human), so enough to do what i want and fit onto an attiny85!, great!. And, i have decided what i am going to do with my HD/SSD, install the SSD, partition it into 22gb, 8gb and 2gb, do an install of windows on the 22gb, then delete the windows install on the HD, de-frag both SSD and HD, install linux onto the 8 and 2gb partition on the SSD, then partition the HD into 900gb for window and 100gb for linux!, i think that should work!

So, currently i have to work on the compile errors from the chen code that is more related to erroneous chopping, work out the registers, then upload to a chip and test!

thanks All

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, so i am at the core of why the code baffled me, and of how to understand what the code does, chen has declared some variables:-

const byte togByte = _BV(ICIE1); //Get the value for toggling the buffer interrupt on/off
volatile byte *TIMSK[] = {&TIMSK1,&TIMSK3,&TIMSK4,&TIMSK5};
volatile byte *TCCRnA[] = {&TCCR1A,&TCCR3A,&TCCR4A,&TCCR5A};
volatile byte *TCCRnB[] = {&TCCR1B, &TCCR3B,&TCCR4B,&TCCR5B};
volatile unsigned int *OCRnA[] = {&OCR1A,&OCR3A,&OCR4A,&OCR5A};
volatile unsigned int *ICRn[] = {&ICR1, &ICR3,&ICR4,&ICR5};
volatile unsigned int *TCNT[] = {&TCNT1,&TCNT3,&TCNT4,&TCNT5};
volatile unsigned int one, two, three, four;
volatile unsigned int *OCRnB[] ={&one,&two,&three,&four};

volatile byte buffer[2][buffSize], buffCount = 0;
volatile boolean buffEmpty[2] = {true,true}, whichBuff = false, playing = 0, a, b;

 

what are all the weird refrences with the * in front of them (timsk is timer isn't it?) and why make arrays out of them? (is that what he is doing?), then the one,two,three

and then he refferences with the pin (being tt)

        if(Volume < 0 ){  *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] >> (Volume*-1); }
        else{ *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] << Volume; }

 

and why is whichbuff a boolian?

playing music is turning a digital signal into analog, so controlling the volume is somehow limiting the bandwidth of the analog signal?

thanks heaps!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You might find this Audio Sample Player useful:

 

http://www.technoblogy.com/show?QBB

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for that!, it answers most of my question, but the prototype uses two pins of the chip for the positive and negative of the speaker, would it be alright to just remove one of the pins and ground the speaker to ground?, i also found a good tut https://arduinodiy.wordpress.com...

I have nearly got rid of all the errors, then to install and test!

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, but then you need a capacitor to remove the DC offset; see the circuit in this article:

 

http://www.technoblogy.com/show?...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, so now i think i understand how it overall works!, that is, the timer is setup at the sample rate of the wav file (being 20khz), then an interrupt is set up and is called on each count, and on each count it takes a bite of the sound (from a sound file) and converts it into a voltage and outputs it to the capacitor, which is hooked up to the speaker, because of the capacitor, the frequency is smoothed a bit, and the sound more smooth to the ear. But why does the page have 4 channels?, Am i correct that frequency is the note of the music, amplitude is the "volume" of the music, but what is 4 channels for? is it because he is playing 4 notes a second?, if so, then wav has 20k channels?

and what does the ">>" in "Temp = Acc[c] >> 8;" do?

Also, as a capacitor does not allow voltage/current to directly flow through it, but acts more like a battery, how does the voltage flow from the chip to ground?

thanks heaps!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Theone6000 wrote:
what are all the weird refrences with the * in front of them (timsk is timer isn't it?) and why make arrays out of them? (is that what he is doing?), then the one,two,three

It's an array of pointers. As a simple example say you had 4 pins and you simply want to refer to them as pin[0]..pin[3] but they are really PORTB3, PORTD2, PORTC7 and PORTA4 then one way you might do this is to have:

volatile uint8_t * pinReg[] = { &PORTB, &PORTD, &PORTC, &PORTA };
uint8_t pinNum[] = { 3, 2, 7, 4 };

To set pin[2] you might use:

* pinReg[2] |= (1 << pinNum[2]);

Reg[2] is PORTC and Num[2] is 7 so this would set bit 7 of PORTC and yet we were able to refer to it simply as [2]. That's the idea here. What the author of this code seems to have failed to spot (and so my example does too) is the utility of using struct{} in C. What you would actually do is:

typedef {
    volatile uint8_t * port;
    uint8_t pin;
} pin_t;

pin_t pin[] = {
    {&PORTB, 3},
    {&PORTD, 2},
    {&PORTC, 7},
    {&PORTA, 4}
};

and then later:

*pin[2].port |= (1 << pin[2].pin);

so you group the register address and the pin number together.

 

Similarly in his code:

volatile byte *TIMSK[] = {&TIMSK1,&TIMSK3,&TIMSK4,&TIMSK5};
volatile byte *TCCRnA[] = {&TCCR1A,&TCCR3A,&TCCR4A,&TCCR5A};
volatile byte *TCCRnB[] = {&TCCR1B, &TCCR3B,&TCCR4B,&TCCR5B};
etc.

he should really have used something like:

typedef struct {
    volatile uint8_t * mask;
    volatile uint8_t * Areg;
    volatile uint8_t * Breg;
    etc.
} timer_t;

timer_t timers[] = {
    {&TIMSK1, &TCCR1A, &TCCR1B, etc},
    {&TIMSK3, &TCCR3A, &TCCR3B, etc},
    {&TIMSK4, &TCCR4A, &TCCR4B, etc},
    {&TIMSK5, &TCCR5A, &TCCR5B, etc},
    etc.
};

then refer to timer[N] and within in timer[N].mask, timer[N].regA, timer[N].regB etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Theone6000 wrote:

But why does the page have 4 channels?

That's in the Digital Music Box which can play up to four notes at once - hence the four channels. The Audio Sample Player article is more appropriate for your application.

Theone6000 wrote:

what does the ">>" in "Temp = Acc[c] >> 8;" do?

It's a shift right, to get the top byte in Acc[c].

Theone6000 wrote:

Also, as a capacitor does not allow voltage/current to directly flow through it, but acts more like a battery, how does the voltage flow from the chip to ground?

The capacitor allows AC through but blocks DC. This protects the loudspeaker from the DC voltage which might otherwise damage it.

Last Edited: Wed. May 11, 2016 - 06:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so, you define port and pin as properties of pin_t, then make pin_t an array, and put the appropriate data into it, then one can reference it later!, yes i agree this is much more clearer!.

 

Ok, i see, to get the appropriate tone of the music at a given time the player can play multiple notes together!,

and, for a current to be ac, it would have to go into the negative, so, the ATTINY85 can have -5 to +5 volts on a pin?, if it were just 0-5v then it is basically a staggered dc current, of which the capacitor would smooth out the harsh edges of the signal and make the signal more "user friendly" to the speaker?

and, whilst on the subject of speaker(8ohm), has anyone actually  run a speaker directly of an ATTINY85 or similar chip, what is the sound like?, how long can the chip sustain a speaker at a decent level?

 

thanks Heaps!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Theone6000 wrote:

Ok, i see, to get the appropriate tone of the music at a given time the player can play multiple notes together!,

Yes, it's 4-note polyphony, like playing four notes at once on a keyboard.

Theone6000 wrote:

and, for a current to be ac, it would have to go into the negative, so, the ATTINY85 can have -5 to +5 volts on a pin?, if it were just 0-5v then it is basically a staggered dc current, of which the capacitor would smooth out the harsh edges of the signal and make the signal more "user friendly" to the speaker?

No, the voltage on the pin goes from 0 to +5v, but the mean voltage is 2.5V, so without a capacitor you would be applying 2.5V to the speaker.

Theone6000 wrote:

and, whilst on the subject of speaker(8ohm), has anyone actually  run a speaker directly of an ATTINY85 or similar chip, what is the sound like?, how long can the chip sustain a speaker at a decent level?

Yes - the speaker I used for the Digital Music Box is 8 ohms.

Last Edited: Thu. May 12, 2016 - 07:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so to clarify, i have to set the timers to 20khz and have an interrupt on each count to process a bit of the wav file and turn it into an analog signal, which, is like a wave sign with the zero or center line offset by 2.5v positive!?

Thus, the sound wave is a great deal of steps that are smoothed into a wave similar to an ac wave. So, a speaker cannot sustain a constant voltage of any sort!?

thanks heaps!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

still got some errors, but can't figure them out, so going to post:-

void StopPlayback(){ playing = 0; TIMSK1 &= ~(togByte | _BV(TOIE1)); if(sFile){ sFile.close(); } }

Attiny85.ino:95:47: error: 'togByte' was not declared in this scope

 

void Play(char* filename, unsigned long seekPoint){
    StopPlayback();
    if(Debug){ if(!wavInfo(filename)){ Serial.println("WAV ERROR"); return; } //verify its a valid wav file
    if(seekPoint > 0){ seekPoint = (SAMPLE_RATE*seekPoint) + sFile.position(); seek(seekPoint); } //skip the header info
    playing = 1; bitClear(optionByte,7); //paused = 0;
    if(SAMPLE_RATE > 45050 ){ SAMPLE_RATE = 24000; if(Debug){ Serial.print("SAMPLE RATE TOO HIGH: "); Serial.println(SAMPLE_RATE); } }
    if(SAMPLE_RATE < 9000){ TCCR0B &= ~_BV(CS10); TCCR0B |= _BV(CS11); }
    else{ TCCR0B &= ~_BV(CS11); TCCR0B |= _BV(CS10); }
    byte tmp = (sFile.read() + sFile.peek()) / 2;
    unsigned int mod;
    if(Volume > 0){ mod = OCR0A >> Volume; } else{ mod = OCR0A << (Volume*-1); }
    if(tmp > mod){
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[0][i] = mod; }
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[1][i] = mod; }
        }
    else{
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer[0][i] = mod; }
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp, mod); buffer[1][i] = mod; }
        }
    whichBuff = 0; buffEmpty[0] = 0; buffEmpty[1] = 0; buffCount = 0;
    noInterrupts();
    timerSt();
    TIMSK1 = ( togByte | _BV(TOIE1) );
    interrupts();
    }
void timerSt(){ TCCR1A = _BV(WGM11) | _BV(COM1A1); TCCR1B = _BV(WGM11) | _BV(WGM10) | _BV(CS10); }

 

Attiny85.ino:121:13: error: 'timerSt' was not declared in this scope
Attiny85.ino:122:16: error: 'togByte' was not declared in this scope
Attiny85.ino:126:32: error: a function-definition is not allowed here before '{' token

 

thanks!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Theone6000 wrote:
Attiny85.ino:121:13: error: 'timerSt' was not declared in this scope Attiny85.ino:122:16: error: 'togByte' was not declared in this scope

 

The function timerSt() and the variable togByte are not visible (i.e. "in this scope") to the function Play(...).

Lots of possibilities exist for this problem: the function timerSt() is not being compiled, it is in another file and perhaps a .h file has not been included, or it is in the same file but after Play(...). The same is probably true for the variable togByte.

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Opps,  i forgot to add it, being:-

const byte togByte = _BV(ICIE1);

 

Chen calls togByte later in the code, and manipulates the timers and counters, the only reason i can think of is he has allowed for people using different sample rate music, as my music will be controled, i can thus delete all the register change stuff after it is set in the setup() (as below)?

 

but, i found some neat code:-
    TCCR0A = (1 << WGM01);             //CTC mode
    TCCR0B = (2 << CS00);              //div8
    OCR0A = F_CPU/8 * 0.000050 - 1;    // 50us compare value
    TIMSK1 |= (1<<OCIE0A);              //if you want interrupt

 

which does what i want, being the 50us, and compiled first go!, the timerSt, is that needed? can i get rid of it all together?

and yes, timerSt was after the call, corrected that, thanks!

 

Chan makes a call to togByte in the stop playing:-

void StopPlayback(){ playing = 0; TIMSK1 &= ~(togByte | _BV(TOIE1)); if(sFile){ sFile.close(); } }

 

and i am guessing that he is stopping the timer so that no more sound could seep and/or continue to play on the speaker pin as there would be no more interrupts!?

if so, could i just make the timer start code above a function, and call it upon play, and on stop do TIMSK1 = 0; ? or is there a specific call to turn off interrupts?

 

chen uses this code, but i am not sure what he is exactly doing, what does the noInterrupts reference? and the interrupts?

    noInterrupts();
    timerSt();
    TIMSK1 = ( togByte | _BV(TOIE1) );
    interrupts();

 

thanks heaps!

 

Last Edited: Thu. May 12, 2016 - 02:44 PM