acaudio/--background--
PURPOSE
acaudio.audio is AHI's driver for ACAHI, AmigaChrome's sound
board (acahi.doc). Programs never open it: they use ahi.device or
AHI's library calls as on any Amiga, and AHI calls this driver
when a unit or a program picks one of its modes. This file says
what the driver does with each of AHI's driver calls, so that a
program's author knows what to expect from each mode.
One m68k binary serves AmigaOS 3.x and AROS 68k. It is a version 6
driver (it uses PreTimerFunc and PostTimerFunc), so it needs AHI
6.
FILES
DEVS:AHI/acaudio.audio the driver
DEVS:AudioModes/ACAUDIO its modes
MODES
0x00AC0001 AmigaChrome: Host mix 16 bit stereo++
The board mixes AHI's channels (up to 32) at 44.1 kHz.
AHI's channel calls go to the board's voices; the 68k
mixes nothing. The mode file sets the driver's own tag
AHIDB_UserBase+0 (HostMix) TRUE.
0x00AC0002 AmigaChrome: HiFi 32 bit stereo++
0x00AC0003 AmigaChrome: 16 bit stereo++
AHI mixes on the 68k with its HiFi or its 16-bit
mixer, at 8 to 48 kHz, and the driver streams what
it mixes to the board.
In every mode the board's sound reaches the PC beside Paula's,
as its own source in Cradle's mixer ("NAME · AHI").
ONE AT A TIME
The board serves one AHI_AllocAudio() at a time. ahi.device's
units are one while any program has them open.
NOT YET
Recording (AHISF_RECORD, AHIDB_Record is FALSE). In Host mix,
echo and DSP masks return AHIE_UNKNOWN; use another mode for them.
SEE ALSO
acahi.doc, docs/howto/08-ahi-sound.md,
AHI's own autodocs (ahi.doc, ahi_sub.doc)acaudio/AHIsub_AllocAudio
NAME
AHIsub_AllocAudio -- take the board for an AHI_AllocAudio()
SYNOPSIS
flags = AHIsub_AllocAudio( tags, audioctrl )
D0 A1 A2
FUNCTION
Finds the ACAHI board (Dalsin or 2011, product 4) and resets it.
tags are the mode's tags from DEVS:AudioModes/ACAUDIO; the
HostMix tag picks how the driver works.
Host mix: checks ahiac_Channels is at most 32 and ahiac_Sounds
at most 1024, and sets
ahiac_MixFreq to 44100, the rate the board mixes at.
The others: keeps ahiac_MixFreq between 4000 and 96000.
Adds an interrupt server on INTB_PORTS, named "acaudio.audio".
RESULT
Host mix: AHISF_KNOWSTEREO | AHISF_KNOWHIFI. Without
AHISF_MIXING AHI sends every channel call to the driver; without
AHISF_TIMING the driver calls PlayerFunc from the board's timer.
The others: AHISF_MIXING | AHISF_TIMING | AHISF_KNOWSTEREO |
AHISF_KNOWHIFI.
AHISF_ERROR when there is no board, the board is in use, the
mode asks for more than 32 channels, or memory runs out.acaudio/AHIsub_FreeAudio
NAME
AHIsub_FreeAudio -- give the board back
SYNOPSIS
AHIsub_FreeAudio( audioctrl )
A2
FUNCTION
Stops playing, removes the interrupt server, resets the board
(which unloads every sound) and frees the driver's data.acaudio/AHIsub_Disable
NAME
AHIsub_Disable -- hold back SoundFunc and PlayerFunc
AHIsub_Enable -- let them run again
SYNOPSIS
AHIsub_Disable( audioctrl )
AHIsub_Enable( audioctrl )
A2
FUNCTION
Disable clears the board's INTENA; Enable sets it back. They
nest: the last Enable is the one that counts. Requests raised
meanwhile wait in the board's INTREQ and are served at the last
Enable; at most four PlayerFunc calls catch up a long wait.
Sound goes on playing: the voices and the stream need no 68k.acaudio/AHIsub_Start
NAME
AHIsub_Start -- start playing
SYNOPSIS
error = AHIsub_Start( flags, audioctrl )
D0 D0 A2
FUNCTION
Host mix: sets the board's master gain, starts the board's timer
at ahiac_PlayerFreq (when there is a PlayerFunc), and starts the
voices. The board's voice events call SoundFunc, and its timer
ticks PlayerFunc, from the interrupt server, as AHI's own mixer
would call them.
The others: starts the driver's task ("acaudio.audio", priority
20). For each buffer it calls PlayerFunc, then PreTimerFunc, then
MixerFunc unless AHI's CPU limit says to skip it (the buffer is
silence then, and the music keeps its time), then PostTimerFunc,
and submits the buffer to the board, which copies
it at once. It keeps three buffers queued, and the board's DONE
interrupt wakes it to mix the next. The music is timed by the
board's audio clock, so it plays at the right speed whatever the
CPU's pace.
RESULT
AHIE_OK; AHIE_NOMEM; AHIE_UNKNOWN for AHISF_RECORD (not yet), or
a mix rate or buffer type the board does not play.acaudio/AHIsub_Update
NAME
AHIsub_Update -- the player's frequency or buffer size changed
SYNOPSIS
AHIsub_Update( flags, audioctrl )
D0 A2
FUNCTION
Host mix: sets the board's timer to the new ahiac_PlayerFreq.
The others: nothing; the task reads ahiac_BuffSamples before
every mix.acaudio/AHIsub_Stop
NAME
AHIsub_Stop -- stop playing
SYNOPSIS
AHIsub_Stop( flags, audioctrl )
D0 A2
FUNCTION
Host mix: stops the timer and the voices. Sounds stay loaded.
The others: stops the task and waits for it to end, then stops
the stream.acaudio/AHIsub_SetVol
NAME
AHIsub_SetVol -- a channel's volume and panning
SYNOPSIS
result = AHIsub_SetVol( channel, volume, pan, audioctrl, flags )
D0 D0 D1 D2 A2 D3
FUNCTION
Host mix: the channel's voice takes volume and pan, now with
AHISF_IMM, else when its sound playing ends (acahi.doc,
ACAHI_V_CMD). A negative volume inverts the sound. The board has
no surround: a negative pan plays as its absolute value.
RESULT
Host mix: AHIE_OK. The others: AHIS_UNKNOWN, so AHI does it.acaudio/AHIsub_SetFreq
NAME
AHIsub_SetFreq -- a channel's playing rate
SYNOPSIS
result = AHIsub_SetFreq( channel, freq, audioctrl, flags )
D0 D0 D1 A2 D2
FUNCTION
Host mix: the channel's voice plays freq frames a second, now
with AHISF_IMM, else when its sound playing ends. AHI_MIXFREQ is
44100. The board resamples with linear interpolation. A freq of
0 pauses the channel, silent, where it is, until another freq.
RESULT
Host mix: AHIE_OK. The others: AHIS_UNKNOWN.acaudio/AHIsub_SetSound
NAME
AHIsub_SetSound -- what a channel plays
SYNOPSIS
result = AHIsub_SetSound( channel, sound, offset, length,
D0 D0 D1 D2 D3
audioctrl, flags )
A2 D4
FUNCTION
Host mix: the channel's voice plays sound from frame offset,
length frames (0: to the end; below 0: backwards), over and
over. With AHISF_IMM it starts now; without, when the sound
playing ends, and that moment calls SoundFunc. AHI_NOSOUND
silences the channel.
RESULT
Host mix: AHIE_OK, or AHIE_UNKNOWN for a sound not loaded or a
part outside it. The others: AHIS_UNKNOWN.acaudio/AHIsub_SetEffect
NAME
AHIsub_SetEffect -- an effect on the mix
SYNOPSIS
result = AHIsub_SetEffect( effect, audioctrl )
D0 A0 A2
FUNCTION
Host mix: AHIET_MASTERVOLUME sets the voices' master gain, which
the driver scales by 2 / channels when there are more than two
channels, as AHI's own mixer does. Cancelling it goes back to
full.
AHIET_CHANNELINFO: after each PlayerFunc the driver fills
ahieci_Offset[] with the frame each channel's sound is playing
(the board's V_POS) and calls ahieci_Func, as AHI's mixer does
after each pass. ahi.device asks for it on every unit it opens,
and a unit does not open without it.
RESULT
Host mix: AHIE_OK for the master volume and channel info,
AHIE_UNKNOWN for echo and DSP masks. The others: AHIS_UNKNOWN, so
AHI's mixer does them all.acaudio/AHIsub_LoadSound
NAME
AHIsub_LoadSound -- tell the board where a sound is
AHIsub_UnloadSound -- forget it
SYNOPSIS
result = AHIsub_LoadSound( sound, type, info, audioctrl )
D0 D0 D1 A0 A2
result = AHIsub_UnloadSound( sound, audioctrl )
D0 D0 A2
FUNCTION
Host mix: loads AHI's struct AHISampleInfo into the board's slot
sound (0 to 1023). The board reads the frames from Amiga RAM as
they play, so AHIST_SAMPLE and AHIST_DYNAMICSAMPLE sounds are the
same to it: a program can keep writing a dynamic sound while it
plays. Unloading silences the channels playing it.
Sample types: AHIST_M8S, AHIST_S8S, AHIST_M16S, AHIST_S16S,
AHIST_M32S and AHIST_S32S.
An ahisi_Address of 0 with an ahisi_Length of 0xFFFFFFFF is AHI's
"all of memory" sound: AHIsub_SetSound's offset is then where
the frames are, checked as each segment starts.
RESULT
Host mix: AHIE_OK; AHIE_BADSOUNDTYPE for anything but a sample
(AHIST_INPUT); AHIE_BADSAMPLETYPE for another sample type;
AHIE_NOMEM for a sound number above 1023; AHIE_UNKNOWN for a
sound not all in RAM. The others: AHIS_UNKNOWN.acaudio/AHIsub_GetAttr
NAME
AHIsub_GetAttr -- what the mode offers
SYNOPSIS
value = AHIsub_GetAttr( attribute, argument, default, tags,
D0 D0 D1 D2 A1
audioctrl )
A2
FUNCTION
AHIDB_Bits 16
AHIDB_MaxChannels Host mix: 32
AHIDB_Frequencies Host mix: 1 (44100); the others: 7
(8000, 11025, 16000, 22050, 32000,
44100, 48000)
AHIDB_Frequency the argument'th of those
AHIDB_Index the nearest to argument
AHIDB_MaxPlaySamples the others: 65536
AHIDB_Record FALSE
AHIDB_FullDuplex FALSE
AHIDB_Realtime TRUE
AHIDB_Inputs 0
AHIDB_Outputs 1, named "Cradle"
AHIDB_Author, AHIDB_Copyright, AHIDB_Version, AHIDB_Annotation
Anything else returns default.acaudio/AHIsub_HardwareControl
NAME
AHIsub_HardwareControl -- levels and inputs
SYNOPSIS
result = AHIsub_HardwareControl( attribute, argument,
D0 D0 D1
audioctrl )
A2
FUNCTION
Returns 0 for everything: the board has no inputs, and its level
is set on the PC, in Cradle's mixer.