home *** CD-ROM | disk | FTP | other *** search
- By: Emil Gilliam
- Re: adlib digitized sound
- ------------------------------------------------------------------------
-
- Okay, here we go with some specifics on how to play digitized sound out
- of the AdLib! Note: If you write a program that uses sound boards, you
- should make it recognize the Sound Blaster and use the Sound Blaster DAC
- if there is one, because it sounds better, so I suggest that you only
- use this method for playing digitized sound out of the AdLib if there
- actually is a real AdLib. (Also, I don't know if this method works
- right on the Sound Blaster, so if there's a Sound Blaster, use the DAC
- instead!!)
-
- Here's how to play a digitized sample out of the AdLib:
-
- 1.) Disable interrupts. (While we change vectors and things)
-
- 2.) Get the old interrupt 8 vector and save it. Set the interrupt 8
- vector to point to a new interrupt 8 handler (which is described below).
- I suggest that you get and set interrupt vectors yourself instead of
- calling DOS to do it, because maybe DOS tries to hook itself into every
- vector somehow (?) and that can be a problem when our new interrupt 8
- vector will be called thousands of times a second.
-
- 3.) Okay, now we're going to set up the AdLib for playing digitized
- sound. As many of you know, the AdLib uses I/O ports 388h and 389h (388h
- is the index register, 389h is the data, and 389h is write-only).
-
- Note: After you write a register number to port 388h, you need to wait
- 3.3 microseconds for the card to respond. After you write a value to
- one of the registers at port 389h, you need to wait 23 microseconds
- before you can write to another register. You can wait 3.3 microseconds
- by doing 6 "IN AL,DX" instructions from port 388h, (I think that each IN
- AL,DX from port 388h will take the same amount of time no matter what
- the speed of the computer is [?] because it takes the card a while to
- get the value of the status register of the AdLib, which is what you get
- when you read from port 388h. But we don't need the value of that
- status register, we just need to IN AL,DX from it 6 times for the 3.3
- microsecond wait.) You can wait the 23 microseconds by doing 35 "IN
- AL,DX" instructions from port 388h. By the way, you should put all
- these IN AL,DX's in a row rather that in a loop, because the loop will
- take time and you'll wait more time than necessary.
-
- Here's how to set up the AdLib card for playing digitized sound. Write
- 21h to register 20h (Sets MULTI=1,AM=0,VIB=0,KSR=0,EG=1 for operator 1).
- Then write 0F0h to register 60h (Sets attack rate to 15 and decay rate
- to 0 for operator 1, makes sense because we want the sine wave to start
- immediately and we never want it to stop), and write 0F0h to register 80h
- (sets the sustain level to 15 and the release rate to 0 for operator 1).
-
- Then, write 01h to register 0C0h. (Feedback=0 and Additive Synthesis is
- on for voice 1 [which is operator 1 and operator 4]). Then write 0 to
- register 0E0h. (Waveform=regular sine wave for operator 1.) Then write
- 3Fh to register 43h (sets total level=63 and attenuation for operator 4,
- don't ask me why this is done, but I do know that operator 4 combines
- with operator 1 to make one of the voices).
-
- Then write 1 to register 0B0h.
- Then write 8Fh to register 0A0h.
- Then write 2Eh to register 0B0h. (Set KEY ON)
- (I don't know why we have the multiple writes to register 0B0h.
-
- This sets the frequency of operator 1, the speed of the sine wave.
-
- 4.) Immediately (right after writing 2Eh to register 0B0h, and
- interrupts are still disabled), wait until 952h 8253 timer ticks have
- passed. I think that what this does is wait for the sine wave being
- generated by operator 1 to get all the way to the top.
-
- 5.) Now that the sine wave of operator 1 is at the top, we're immedia
- tely going to change the frequency of operator 1 to 0, so that the sine
- wave is stuck at the top. Write 20h to register 0B0h and write 0 to
- register 0A0h. The 20h in register 0B0h keeps operator 1 in KEY-ON
- state.
-
- 6.) We're almost done setting up. Divide 1193180 by the number of
- samples per second and write that value into timer channel 0 (of the
- 8253 chip). This will change the number of times per second interrupt 8
- is called to the number of samples per second. Interrupt 8 is going to
- be called for each sample, and it will play one sample each time it's
- called.
-
- 7.) Enable interrupts, and wait until the sample is done playing. (Your
- interrupt 8 handler should set some sort of flag when it's done.)
-
- 8.) Disable interrupts, set the interrupt 8 vector to what it used to
- be, write 0 to 8253 timer channel 0 (to make interrupt 8 go 18.2 times a
- second), and we're done!
-
- -----
-
- Okay. The new interrupt 8 handler should do this.
-
- 1.) Save any used registers. (I know that the CPU will probably be in
- the waiting loop when interrupt 8 is called, and the waiting loop might
- use no registers, but save registers just to be on the safe side because
- the CPU might be in the middle of processing a keyboard interrupt or
- something like that.)
-
- 2.) Get a 6-bit sample from the digitized sound sample. (If you have an
- 8-bit sample, just shift each sample right two bits. I assume that'll
- be the case because you can write a program to play digitized sound that
- writes values to the Sound Blaster DAC if there is a Sound Blaster and
- use this method if there is an AdLib.) Write that number to register
- 40h. (The top 2 bits should be 0).
-
- Note: An alternative is to have the initialization code write 40h to
- port 388h right before enabling interrupts, and then all that the
- interrupt 8 handler has to do is write values to port 389h instead of
- having to write 40h to port 388h every time.
-
- 3.) Write 20h to port 20h (8259 non-specific EOI), restore any used
- registers, and get the heck outta there with IRET.
-
- -----
-
- The only problem with this is that the computer's clock will be held
- while the sample is playing, because the regular interrupt 8 isn't
- executing while the sample is playing, but if that's a problem you can
- circumvent that yourself by getting the length of the sample and adding
- that to the computer's time when you're done, or by possibly getting the
- CMOS time. That's something I still don't know, on AT's does the
- computer get the time from the CMOS whenever you have to get the time,
- or does the computer just get the time on bootup and write that into
- some low-memory address for interrupt 8 to increase every time it's
- called? On AT's, does interrupt 8 even increase any time variables at
- all? Does it need to? If anyone knows anything about that, please let
- me know.
-
- -----
-
- The playing of digitized sound out of the AdLib doesn't have to use
- operator 1, it can use any operator. It just has to use the same
- operator all the way through. (Except for when you write 3Fh to
- register 43h, don't ask me why that was in what I disassembled... but
- if you change operator numbers, you'll have to change this reference to
- operator 4 to the operator that the other one is "paired up with"...)
- That means that you can play digitized sound and music at the same time
- out of the AdLib! Just play digitized sound as usual and while waiting
- for the sample to play, use the other voices to play music! You can
- even play two samples at the same time by using two different operators
- and having your interrupt 8 handler write values to both! Theoreti
- cally, you can play as many samples as you want and music at the same
- time... I'm sure that in practice that would be VERY hard to pull
- off... almost more trouble than it's worth... but maybe someone should
- give it a try!
-
-
- And there you have it. I hope that THAT is pretty complete! But if
- anyone still needs any more information, like on how to read or write to
- the 8253 timer chip, let me know.
-
- Emil Gilliam
-