Forum: Mikrocontroller und Digitale Elektronik Wiederholte Soundausgabe mit AVR


von Axel L. (ligonap)


Lesenswert?

Hallo Zusammen

beim Lesen des Beitrag "Sprachausgabe mit AVR" aus dem 
letzten Jahr, kam mir eine Frage in den Sinn. Ich möchte aber meine 
Frage nicht in diesen Beitrag setzen, da er eigentlich abgeschlossen 
ist.

Die Programme von "Holger Klabunde" und "Ingo Laabs" benutzen zwei Timer
(CTC & PWM) für die Sound-Ausgabe von WAV-Dateien. In beiden Fällen wird 
die Audio-Datei vollständig, z.Bsp. nach einem Event, abgespielt.

Gibt es eine Möglichkeit eine Audio-Datei (WAV oder RAW) vor seiner 
Beendigung zu wiederholen, ohne dass die erste Datei abgeschnitten wird? 
Quasi eine Art Cross-Fading.

Vielen Dank und Grüße
Axel

von Axel L. (ligonap)


Lesenswert?

Bei meinen Versuchen, bin ich auf eine Merkwürdigkeit gestoßen.

In der Regel werden im Hauptprogramm die Doppelpuffer zur Sound-Ausgabe 
gefüllt und mittels ISR (Overflow oder Compare Match) an OC... 
übergeben. So weit so gut. Klappt einwandfrei. Hacken ist hierbei, keine 
anderen Aktionen im Hauptprogramm können durchgeführt werden, bis die 
Datei komplett abgespielt ist.

Aus diesem Grund habe ich sowohl das Einlesen als auch die Ausgabe in 
die ISR-Routine gelegt. Eine Ausgabe findet auch statt, aber eine Art 
Vibrator überlagert die Ausgabe. Ähnlich, wie hier beschreiben: 
Beitrag "Sprachausgabe mit AVR"

Egal ob ich zwei Overflow vom Timer1 und/oder Timer2 oder zwei Compare 
Match vom Timer1 und/oder Timer2 nehme, ich bekomme immer diesen 
Vibrator-Effekt. Dieser Effekt hält solange an, wie die Timer für PWM 
und CTC an sind. Unabhängig davon, wann ich die Datei schließe. 
Unabhängig davon, ob der Puffertausch innerhalb der Ausgabe-ISR oder 
beim Einlese-ISR liegt.

Weiß jemand Rat??

Hier mal beispielhafter Code:
1
#define PLAY_BUFFER_SIZE   256
2
3
uint8_t* playBuffer = BufferA;   
4
uint8_t* readBuffer = BufferB;   
5
6
uint16_t actByte;
7
uint8_t  bufferChanged;
8
9
10
ISR(TIMER1_COMPA_vect)
11
{
12
OCR0A = playBuffer[actByte++];  
13
}
14
15
ISR(TIMER0_COMPB_vect)
16
{
17
if( actByte == PLAY_BUFFER_SIZE ) {  
18
19
     uint8_t* tmp = playBuffer;    
20
     playBuffer = readBuffer;      
21
     readBuffer = tmp;             
22
     actByte = 0;                  
23
     Fread(readBuffer,PLAY_BUFFER_SIZE);
24
   }
25
}

von Karl H. (kbuchegg)


Lesenswert?

Während eine ISR läuft kann keine zweite ISR laufen.
Das hier
     Fread(readBuffer,PLAY_BUFFER_SIZE);
dauert zu lange.

von Karl H. (kbuchegg)


Lesenswert?

> Hacken ist hierbei, keine
> anderen Aktionen im Hauptprogramm können durchgeführt werden, bis die
> Datei komplett abgespielt ist.

Warum nicht?

Die TIMER0_COMPB_vect ISR setzt ein Flag, dass der nächste Buffer 
nachzuladen wäre und bei passender Gelegenheit macht das die 
Hauptschleife in main(). Lange Aktionen dürfen natürlich nicht in der 
main gemacht werden, so dass die ABfrage ob der Buffer nachgefüllt 
werden muss entsprechend häufig ausgeführt wird. Aber dieses Problem hat 
man generell bei allen Formen von "Multitasking" mittels Event-Flags.

Aber abgesehen davon ist das eine ganz normale Geschichte, die mittels 
Event-Flags in der Hauptschleife gelöst wird.
1
volatile uint8_t loadNextBuffer;
2
3
ISR(TIMER0_COMPB_vect)
4
{
5
if( actByte == PLAY_BUFFER_SIZE ) {  
6
7
     uint8_t* tmp = playBuffer;    
8
     playBuffer = readBuffer;      
9
     readBuffer = tmp;             
10
     actByte = 0;                  
11
     loadNextBuffer = 1;
12
   }
13
}
14
15
int main()
16
{
17
   ....
18
19
20
  while( 1 ) {
21
22
    if( loadNextBuffer ) {
23
      Fread(readBuffer,PLAY_BUFFER_SIZE);
24
      loadNextBuffer = 0;
25
    }
26
27
    .....
28
29
  }
30
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.