View Full Version : Doing a read while in an intr handler

01-13-2002, 08:30 PM
I'm writing a sound system for DOS real mode. The program hangs under DOS when the interrupt is generated. Can you do a read() inside of an interrupt or will this cause DOS to re-enter itself?

Problem is that real mode cannot just load all of the samples into memory all at once so I'm caching from the disk. Each sample has a 8192 bytes buffer to cache with. The DMA transfer is 4096 bytes. Slow because of the read(), but the other alt is EMS which is not hard, but haven't done it yet.

So on interrupt I'm reading in a new block of data in the block that just played, mixing it, and playing the block that was just loaded. The read() is causing the system to freeze with the disk hard disk light on. When I comment it out, everything works and I send ACK to the DSP and EOI to the PIC and everyone gets along fine.

If I cannot read while inside of an interrupt (also cannot do a printf()) then I guess I will have to go PM or use EMS.

Is there any other way to do this?

I think DOS is re-entering itself but I cannot CLI because read requires a DOS interrupt just like printf. Since both of these functions cause the system to crash and will even bring Windows to its knees this is my take on what's happening.

No errors or warnings in compile and circular buffer works fine.



At point 1 I set the PlayOffset to 4096 and the LoadOffset to 0.
Load all samples from their respective files and mix all sample buffers into one global sample output buffer.

At point 2 I set the PlayOffset to 0 and the LoadOffset to 4096.
Load all samples from their respective files and mix all sample
buffer into one global sample output buffer.

The whole cycle continues until done playing(point 2 is the same as the start point of the diagram).

01-14-2002, 12:30 PM
From within an ISR, you should be looking to do as little work as possible, and you shouldn't be calling something like read(), which takes a long time, and also re-enters DOS (as you've already noted). Basically, anything which could block, take a long time, or calls DOS is probably a no-no.

The normal way (I think) is a double buffer arrangement, where the ISR just reads from one buffer, and when that's done, flips over to the other.
A periodic check inside your main program detects this change, and issues the read request to fill the now vacant buffer, hopefully before the ISR reaches the end of the previous buffer.

The size of the buffer depends on
a) how fast the ISR gets through the data
b) how fast you poll for a change of buffer, to trigger the re-fill
c) how fast the buffer can be filled with a read() call.

01-14-2002, 04:20 PM
Well, my sound system does work in a DOS shell, but not in pure DOS. The read() does cause DOS to re-enter itself and the whole thing comes crumbling down. I'm only reading 256 bytes and transferring half that to the DMA using a circular buffer. I altered my buffering structure a bit from my last post. The handler loads into the block that just played while the DMA is set to auto init. It just loops and loops while my int handler fills the block that just played with info from the sample. Fill behind and play ahead. So, once the DMA is set in motion it will not stop until I stop it at the end of the longest sample in the mix. The DMA automatically loops so I never have to reprogram it, thus stopping the sound.

So far it works great and can mix an unlimited number of samples with very good audio quality. Of course, the more samples, the quicker the values will go out of range and possibly cause distortion. Only occurs when there are more than 8 or 9 samples playing at once.

Since my DMA buffer is so small, you can add samples to the mix almost at any time since it takes almost nothing to transfer 256 bytes.

I'll try to implement what you said, though, so it will work in pure DOS.