Wiederholte Soundausgabe mit AVR

OP #2261983
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
OP #2272990
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
}
#2273009
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren