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
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 | }
|
Während eine ISR läuft kann keine zweite ISR laufen. Das hier Fread(readBuffer,PLAY_BUFFER_SIZE); dauert zu lange.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.