16 January 2020, 01:29 | #1 |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Cannot use AUDX-INT (Level 4 IRQ) to stop sample.
Hi there!
Since I have some days off I play around with 68K assembly. What I want is to play samples one time and than it should stop or bet stopped. Unfortunately, I have a behavior I don't understand. I wanted to use Level 4 interrupts (AUDx) to stop the sample which was started via DMA. My understanding was whenever the last data-word was read a Level 4 INT for the channel is issued. My handler code loooks like this: own_level4_handler: Code:
movem.l d0-a6,-(a7) ; waste some time - but show it move.w #$0fff,$180(a6) ; WHITE flash move.w #$2ff,d0 ; wait x lines to waste some time bsr.w loop_n_time move.w #$0000,$180(a6) ; back to black ; The plan was to stop DMA of channel 0 by: ; move.w #$0001,$096(a6) ; AUD0 DMA off move.w #$0080,$09c(a6) movem.l (a7)+,d0-a6 rte Code:
; in a4 is the vbr lea own_level4_handler(pc),a1 move.l a1,$70(a4) Code:
move.w #$c080,$9a(a6) ; intena-wr SET:INTEN--|---AUD0|----|---- the sample plays continuously of course and the screen flashes white on different locations since DMA-switch-off is disabled. That's what I expected. BUT when I enable the line: 'move.w #$0001,$096(a6)' to stop the AUD0-DMA I hear NOTHING at all - it seems that the DMA is instantly stopped. Furthermore I see 3 white areas on the screen which indicates that the IRQ-handler is called 3 times consecutively. WHAT am I doing wrong. Any help much appreciated. Thanks. Last edited by Herpes; 16 January 2020 at 01:33. Reason: removed the font-tags |
16 January 2020, 04:25 | #2 |
Registered User
Join Date: Nov 2017
Location: Los Angeles
Posts: 49
|
The Audio interrupt triggers not at the end of playback, but rather shortly after the start when the audio registers have been internally copied. This allows you to queue the "next" waveform shortly after the start of the current one so that you can have seamless playback.
In your interrupt, you are stopping the DMA at the very start of playback, which is why you no longer hear anything. As I understand it, the correct way to stop the audio from looping is in the interrupt to set it to point to a short and "empty" sample so the "next" sample plays nothing. If you really want to stop DMA entirely, then you'll need to do that on the second interrupt (for the start of the "empty" sample). You usually need to track some global state for your interrupt to know what state a given channel is in and what you should do. Last edited by FSizzle; 16 January 2020 at 04:38. |
16 January 2020, 09:18 | #3 | |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
First, thanks for your quick answer.
I have to test your approach - I had this in mind but did not give it a chance because I thought I would trigger another Interrupt when I initialize the empty sample. BUT OK, if it is like you say - then I misinterpreted the Amiga-HRM. Quote:
Furthermore it does not make much sense to trigger after the start since this is the exact time I know anyway since I just kicked off the sample. So I am not sure where my mistake is. Anyway, thanks to your input I can experiment a little without being too frustrated. Last edited by Herpes; 16 January 2020 at 09:18. Reason: typo |
|
16 January 2020, 12:21 | #4 |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
CHEEESSSSS!
It seems you are right! I cannot believe it! Now I used a bit longer sample, started its DMA and immediately its AUDx channel INT was triggered. To achieve a single-shot-sample using the IRQ handler I have to ignore the first INT. Then when the sample restarts I process the INT and switch off the DMA to stop it. That works so far... Haha, BUT doing that during the INT leads IMMEDIATELY to another execution of the INT-handling routine again - unbelievable! My code might be broken but this is it: Code:
own_level4_handler: ; AUD0 INT ocurred - because no other Level4 INT is allowed movem.l d0-a6,-(a7) ; save all registers move.w #$0080,d0 ; erase IRQ bit: off---|----|AUD0---|---- move.w d0,$dff09c ; intreq (write) move.w d0,$dff09c ; twice to avoid a4k hw bug lea aud0_cnt(pc),a0 ; fetch the counter to ignore first INT move.w (a0),d1 bne.s .process_irq addq.w #1,d1 move.w #$0f00,$180(a6) ; RED flash to indicate ignorance of INT move.w #$02ff,d0 ; wait 767 loops to waste some time bsr.w loop_n_times move.w #$0000,$180(a6) ; back to black bra.s .exit_aud0 .process_irq move.w #$0fff,$180(a6) ; WHITE flash to indicate processing of INT move.w #$02ff,d0 ; wait 767 loops to waste some time bsr.w loop_n_times move.w #$0000,$180(a6) ; back to black move.w #$1,$dff096 ; switch OFF the DMA for J.Miner's sake! moveq #0,d1 ; rest counter to ignore next INT. .exit_aud0 move.w d1,(a0) ; store irq count movem.l (a7)+,d0-a6 ; restore all registers rte aud0_cnt: dc.w 0 [1] First_INT_Trigger.png [2] Second_INT_Trigger.png @First_INT_Trigger - you see I triggered the start of the sample. which can be seen by the purple area, followed immediately by the red area which is the IGNORED AUD0-INT. @Second_INT_Trigger - you see there are TWO WHITE areas. IMO this is BECAUSE when switching OFF the DMA triggers an AUD0-INT as well, BUT obviously it must have been triggered BEFORE I could reset the counter 'aud0_cnt', otherwise the are would have to be RED. For me this is completely strange and show that I did not understand ANYTHING of the documentation of the HRM. Maybe ANYONE can explain these findings or tell me what I have done wrong? I will check a physical Amiga and test this once more I would be happy if that's only an emulation problem. Any hints are highly appreciated. |
16 January 2020, 12:26 | #5 |
son of 68k
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
|
There is an audio intreq not only when a sample starts playing, but also when it stops.
|
16 January 2020, 12:40 | #6 |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Yes, looks like that - although the HRM docs says something different.
But with 'stopping' you mean stopping the DMA. Because, I don't get 2 INTs when the sample restarts (one slightly before and one slightly after restart), but when I actively stop the DMA. Anyway according to the documentation from the HRM the INT should be triggered when last word of sample was accessed. This would make sense because otherwise I don't know when it is over and cannot easily stop it. But with the behavior shown it looks like I ONLY get an INT when the AUDx DMA starts AND I switch off the AUDx DMA but definitely NOT when the sample reached its end and is about to be restarted. Anyway I can live (and of course have to) with the triggering of the INT at start of the sample. I am just stunned about the documentation AND about the feature that when stopping the AUDx-DMA that a AUDx-IRQ is issued. |
16 January 2020, 12:46 | #7 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
"Joining tones" section in audio chapter explains it better.
When channel starts, interrupt is generated when first word has been DMAd. When sample ends (=first new word of next sample has been already DMAd and about to start playing), interrupt is also generated. |
16 January 2020, 13:13 | #8 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
This is how I see it in my head and which allows me to understand how it works (which is logically as Toni said).
I hope it helps you and can clarify things a little better When you write the AUDxLEN/PER values and activate the DMA, at the next fetch of the DMA channel the 'internal' LEN counter is at 1 (attention: 1 not 0!), triggers an IRQ and then reloads the value that you have set (buffered) in the custom register. (EDIT: even if you set a large PER, first DMA fetch is at the next audio DMA slot available, so max ~ a video line) This allows to immediately reload new pointer value for the next concatenated sample that will be used the next time LEN counter goes to 1. The length of the audio buffer is always respected because it's always a fetch 'ahead' (the fundamental point is that it never count down to 0 but trigger at 1). EDIT2: in practice it's the internal transition that would bring from the value 1 to 'virtual' 0 that triggers the IRQ and that reloads the register buffered value of LEN. This also allows you to even have a value of 0 for the LEN, a sample exactly 128k long Last edited by ross; 16 January 2020 at 13:58. |
16 January 2020, 14:34 | #9 | |||
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Quote:
The thing which threw me into confusion is that this is just fundamentally different as one expects when reading about it in the HRM (which is official doc) ... I once more stress to quote here: Quote:
[QUOTE]When the audio DMA is operating in automatic mode, this interrupt occurs when the *first* word in an audio data stream has been accessed.[QUOTE] Anyways I now learned through confusing and your input that the IRQ is issued when the channel starts. Thank you for your help. This alone does NOT explain everything - namely the triggering of the AUDx-IRQ handler when one turns OFF the enabled DMA. When one just executes the following line of code in the AUD0-IRQ-handler: Code:
move.w #$1,$dff09 What started my confusion was my initial idea to do the switch-off in the handler - unfortunately and now I understand - one does not hear anything because of the immediate switch-off after the DMA was started With your explanations and the experiments done I conclude it should be documented like this: Quote:
Anyway - this forum always is a great help! Thank you very much. Last edited by Herpes; 16 January 2020 at 14:39. Reason: thanks |
|||
16 January 2020, 14:53 | #10 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
So you do not have a DMA fetch but IRQ You need to stop immediately the trigger, disabling through INTENA. |
|
16 January 2020, 16:33 | #11 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Ok, written a brutal snippet to test it:
Code:
lea $dff000,a0 move.w #$7fff,d0 move.w d0,$9a(a0) move.w d0,$9c(a0) move.w d0,$96(a0) move.l #i4,$70.w move.l #smp,$a0(a0) move.w #(eraw-smp)>>1,$a4(a0) move.l #$02000040,$a6(a0) move.w #$8201,$96(a0) move.w #$c080,$9a(a0) stp bra.b stp i4 lea $dff000,a0 subq.w #1,cnt bpl.b .ex move.w #$80,$9a(a0) move.w #1,$96(a0) .ex move.w #$80,$9c(a0) move.w #$80,$9c(a0) rte cnt dc.w 5 smp dc.w 0 raw incbin "audio.raw" eraw |
16 January 2020, 16:50 | #12 | |
Registered User
Join Date: Nov 2017
Location: Los Angeles
Posts: 49
|
The HRM is confusing in places, and this is certainly one of them. As Toni says, the "joining tones" section is probably the best description of the behavior for "automatic" mode (DMA based sample fetching).
Quote:
If you ignore the first interrupt, the second interrupt is the sample restarting playback. Your interrupt must stop the DMA before any data is read, which generally means it must happen very quickly (probably within less than one raster line). Failure to do it quickly enough will result in audio pops. On the 68000, servicing an interrupt reliably within one raster line can be tricky, if you consider: - the CPU invoking the interrupt alone is quite expensive (storing CPU state takes quite a lot of cycles even before the first instruction of your interrupt) - you have to save registers in your interrupt handler - other DMA going will compete with your interrupt routine (copper, bitplane fetch, sprites, blitter, audio, disk etc), assuming you're running from code in memory on the chip ram bus - you may have other higher priority interrupts already running - you might have multiple samples start on the same raster line Some of these issues might be mitigated if you are targeting a faster CPU or running from fastram, but I think it's ultimately still unreliable (EDIT: It might even be that the interrupt triggers after the fetch of the first pair of samples (i'm not sure about this) in which case you'd also have to make all your samples contain leading zeros to avoid pops) |
|
16 January 2020, 17:11 | #13 |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Wow, yes, that's a lot to consider.... and everything makes sense. I just wonder how the replay routines do all the tricks - never had the interest to dig in... but maybe now.
|
16 January 2020, 17:25 | #14 | |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Quote:
The thing is the code is very similar to the code I tried after you mentioned that in you post unfortunately it does not stop the replay - at least not on my 'machine' which actually is an emulator... I will recheck later. EDIT: what you mentioned works - I just was too eager and made the error to enable the interrupts in the Interrupt-handler again - which is not a good idea ;-) Actually your code also ignores the first N interrupts. So I will use the idea of switching AUDx-INTs off in the handler. This spares one extra trigger. Last edited by Herpes; 16 January 2020 at 22:10. Reason: Ross' code works - \o/ |
|
16 January 2020, 17:52 | #15 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
It use IRQ3 (or 2 or 6 if CIA timed). You can find IRQ4 used by some non-usual replay routines that mix samples, so two little double buffer replenished alternatively when one another is exhausted (the duration time required for a effect/note change). |
|
16 January 2020, 18:53 | #16 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
HRM audio state diagram will explains almost everything but it isn't that simple to understand.
|
16 January 2020, 19:34 | #17 |
Registered User
Join Date: Jan 2012
Location: USA
Posts: 372
|
Interrupt latency depends on when interrupt pins are sampled and this is instruction dependent.
Worst case is MOVE.L all regs followed by DIVS -- over 300 cycles. MOVEM.L samples pins at beginning of instruction while DIVS samples at the end. |
16 January 2020, 22:33 | #18 | |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Quote:
CIA-Timers that's the next hot topic - a pandora's box - I will open ;-) never tried them so far. |
|
16 January 2020, 22:37 | #19 | |
... aka Amix73
Join Date: Jan 2009
Location: Austria
Posts: 87
|
Quote:
Pointing out the state diagram I gave it a quick glance - only 5 states are of interest so it can't be that complicated, can it? I have to give it a read. Thanks. |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Spurious PORTS irq | ross | Coders. Asm / Hardware | 37 | 27 February 2019 20:20 |
Irq Blitter | LeCaravage | Coders. Asm / Hardware | 9 | 16 June 2017 10:21 |
VBCC: complain about static int (*calltrap)(...) = (int (*)(...))0xF0FF60; | mbergmann-sh | Coders. C/C++ | 3 | 17 March 2017 01:19 |
IRQ Virus | redblade | request.Apps | 8 | 01 September 2012 08:22 |
How to stop sample playback ? | AmiGer | Coders. General | 6 | 11 December 2004 10:44 |
|
|