The Audio Hardware ~~~~~~~~~~~~~~~~~~ Introduction ~~~~~~~~~~~~ A loudspeaker is a device that converts an analogue signal into a series of compressions and rarefactions that the human ear perceives as sound. The audio hardware on the Amiga takes a byte of data from memory, converts it into an analogue signal and sends it to the output sockets from where it will travel via an amplifier to a loudspeaker. The byte of data read from the Amigas memory represents the amplitude of the sound. The Amiga audio hardware interprets each byte as an individual amplitude with a value between -128 and 127. The audio DMA reads data from memory one word at a time, ie two samples. The frequency at which words of data are read from memory, the sample period, determines the note of the sound. Each audio DMA channel has one slot per raster line of the display, so there is an upper limit to the replay frequency of 1 word per raster line. The sample period is expressed as the number of bus cycles between samples so the smaller the sample period, the faster the sample is played. The smallest value allowed is 124. The volume of the sound can also be controlled and can have a value ranging from 0, no volume, to 64, maximum volume. The block of memory that the audio hardware is playing is called a sample. These days most samples are generated by digital samplers that take snapshots of a sound at regular time intervals and convert the snapshot into a byte of data ( -128 to 127 ). The frequency at which snapshots of the sound are taken by the digitiser is known as the sampling frequency. The higher the sampling frequency, the better the digital representation of the sound and more memory occupied by the sample. Audio DMA Registers ~~~~~~~~~~~~~~~~~~~ The simplest way to generate sound on the Amiga is use audio DMA. To do this you need to know about the DMA registers. The Amiga has four audio DMA channels. Each DMA channel has hardware registers that are are used to initialise it. The names of the registers are identical except for the channel number. When discussing registers generally, I will omit channel numbers from the register name and replace it with an x. For example AUD0VOL is referring to the volume register for channel 0, AUDxVOL is referring to the volume registers in general. AUDxLCH Write the start address of a sample to this register pair. AUDxLEN Write the number of words in the sample to this register. AUDxPER Write the sample period to this register. AUDxVOL Write the volume to this register. Playing A Sample Using Audio DMA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To play a sample using audio DMA first the audio registers need to be initialised, then the required DMA channel should be enabled. Once a DMA channel is enabled, the audio device copies the values from AUDxLCH and AUDxLEN into internal registers and starts playing the sample. When a sample has been played once, the process is repeated. The result is a sample will play over and over until the DMA channel is disabled, or the address and length of a new sample is written into the AUDxLCH and AUDxLEN registers. If new values are written to AUDxLCH and AUDxLEN while a sample is playing, the audio device will not fetch the new values until the current cycle has finished. Writing new values to AUDxPER and AUDxVOL has an immediate effect on the sample being played. To stop a sample the DMA channel must be disabled. The first example demonstrates how a sample is played over and over until the DMA channel is disabled. When run, a sample is played through channel 0 and the program waits for the user to press the left mouse button. When the left mouse button is pressed, the DMA channel is disabled. The raw sample data is loaded into the source in the same way as raw graphics data would be, using 'incbin'. Note how the assembler is used to calculate the length of the sample, remember that shifting right ( using the >> operator ) 1 position is equivalent to dividing by 2. The assembler shifts the byte size of the data right, thus forming the word size. The second example initialises two audio channels, each with a different sample. Both DMA channels are started at the same time. Both sounds continue to play until the left mouse button is pressed. The third example starts a sample playing through channel 0. When the right mouse button is pressed, the address and length of a new sample are written to AUD0LCH and AUD0LEN. Note that this sample will not start playing until the first sample completes it's current cycle. Playing A Sample Once ~~~~~~~~~~~~~~~~~~~~~ For spot effects a sample should play only one cycle, and not repeat indefinitely. To achieve this, a small trick is required. As stated above, if new values are written to AUDxLCH or AUDxLEN while a sample is playing, the audio hardware waits for the current sample to finish before fetching the new data. The trick relies on this to work. Make sure every sample starts with a zero word of data, ie no amplitude. As soon as the sample is started, write 1 into the AUDxLEN register for the sample. As the address of the data has not been modified, the same sample will be used. However, the audio hardware will use the new length, 1 word, and so continue to play the first word of data in the sample from this point on. The first word of data is zero, has no amplitude and so cannot be heard. The net result is that the sample is played only once! Example 4 demonstrates this technique in action. Note how the zero word is positioned before the incbin statement in order for the trick explained to work. Try removing the 'dc.w' statement and see what happens. A Spot Effect System ~~~~~~~~~~~~~~~~~~~~ Imagine the scenario, you are writing a game in which a player can fire photon torpedoes from a ship. Every time a torpedo is fired a sample is to be played. It is quite probable that a player can fire torpedoes faster that the fire sample takes to play. So when a torpedo is fired, any sample playing must be stopped and a new sample started. This poses a problem. According to the Hardware Reference Manual, there must be a delay of at least two sample cycles ( time taken to fetch and play one word of data from a sample ) between stopping and restarting DMA on an audio channel. If this criteria is not met, the original sample will continue playing until it has completed it's current cycle before the new sample starts. In other words the current sample will not be interrupted and the new sample will not start until the current sample finishes. The control code of most games and demos operates from a VBI handler, so it makes sense to take advantage of this. The time between two vertical blank intervals is more than enough to satisfy the above criteria, so a sample player that can be inserted into a VBI handler needs to be developed. The sample player about to be described has been kept very basic. It only handles one channel and there is no priority system applied to samples being played. In a game a more advanced sample player would probably be required, if only to utalise all four channels! The sample player will be developed as a subroutine that should be called at some point during each VBI. The routine will load a long word from a predefined memory location, if this long word is zero no action will be taken and the routine will exit. If the long word is non zero the routine will assume it is the address of a simple sample structure and it will play the sample once, as explained above. ******************************** ***** Sample player, first part of spot effect system SamplePlayer move.l Chan0,d0 get addr of sample beq NoNewSample exit if not one move.l d0,a0 a0->structure ; Initialise audio channel 0 move.w (a0)+,AUD0LEN(a5) sample length move.l a0,AUD0LCH(a5) samples address move.w #$12c,AUD0PER(a5) sample period move.w #$64,AUD0VOL(a5) sample volume ; Now start channel 0 DMA move.w #SETIT!DMAEN!AUD0EN,DMACON(a5) start DMA ; Now initialise a quiet sample move.w #1,AUD0LEN(a5) ; Clear this sample request move.l #0,Chan0 clear request NoNewSample rts and exit ******************************** To accompany the sample player, a routine is needed that will stop the sample currently playing on the designated channel and write the address of a new sample into the location examined by the sample player. Whenever a section of code wishes to start a sample playing, it calls this subroutine. ******************************** ***** Sample Request, final part of spot effects system ; Entry a0->sample structure to play PlaySFX move.l a0,Chan0 set sample to play move.w #AUD0EN,DMACON(a5) stop current sample rts ******************************** In order for the above system to work it is necessary to call the sample player before any sections of code that may request a sample be played, otherwise there is a good chance you will be trying to stop and then restart the Audio DMA channel to quickly and it will ignore you! The sample structure used in these routines is arranged as follows: SampleLength word length of sample SampleData the raw data for the sample. Below is an example structure. Sample1 dc.w Smp1Len length of sample Smp1 dc.w 0 incbin 'sample1.raw' raw data Smp1Len equ (*-SMP1)>>1 word length Example 5 demonstrates the above spot effect system in operation. Press the fire button to play a sample, then try holding the fire button down. Note that there is a delay in the CheckFire routine that forces a wait of at 3 Vertical Blanking Periods between each test of the fire button. Try reducing/enlarging this value. Supplied Spot Effects System ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Finally there is a spot effect player supplied in the file HW_Sound.i that is based loosely on the above example. It uses a player routine that should be called first during each VBI and there is a routine that will specify what sample is to be played and through which audio channel. The system uses a new sample structure that is more memory conservative than that used previously and also allows the frequency of the sample to be specified so that fine tuning can be applied. The structure is shown below: Frequency WORD replay frequency of sample Length WORD WORD length of the sample Address LONG address of raw sample data The raw sample data is no longer part of the sample structure. This allows many structures to share a single sample and each could use a different replay frequency. This new structure need not be located in CHIP memory, only the sample data itself! The two subroutines supplied are SEPlayer and SEFX. SEPlayer should be called first during a VBI handler, it requires no entry parameters and returns no useful information. SEFX should be called by parts of your program that want to launch a sample playing. The address of the sample structure should be passes in register a0, and the channel number to play it through in register d0. If you attempt to change the sample being played through a channel every VBI, do not be surprised if you do not hear much! The samples never have time to get going, after all you cant produce much of a sound in 1/50th of a second. Example 6 demonstrates how to use the spot effects system found in HW_Sound.i. The program monitors the joystick from within a VBI handler and a different sample is played for each of the four possible directions of movement. Run the program and start wiggling that stick! Note these points in the program: 1. You must press joystick button to quit! 2. There is a counter that regulates how many VBI's occur before checking movement of joystick ( try altering the counter reset value ). 3. Only one binary sample is used by the program. Foot Note ~~~~~~~~~ You could write a program that monitored the keyboard and acted on which keys were being pressed. Pressing a key would cause a sample to be played at a predetermined frequency. By storing timer values ( VBI counter ) between keystrokes and frequency values you could produce a simple sequencer of your own! --- End of File ---