Writing sound drivers for KolibriOS: Difference between revisions
No edit summary |
(Fixes for <asm> tags - replaced with <syntaxhighlight>) |
||
(2 intermediate revisions by one other user not shown) | |||
Line 3: | Line 3: | ||
== Layers == | == Layers == | ||
[[File:sound_layers.gif]] | [[File:sound_layers.gif|thumb|250px]] | ||
An application wich wants to output sound has to: | An application wich wants to output sound has to: | ||
Line 11: | Line 11: | ||
# Update the sound samples in the buffer. | # Update the sound samples in the buffer. | ||
Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj. | Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj. | ||
When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises. | When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises. | ||
Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable. | Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable. | ||
Sound.obj is responsible for calling this callback function every time the buffers need to be refilled. | Sound.obj is responsible for calling this callback function every time the buffers need to be refilled. | ||
The driver, sound.obj will do this when it gets an interrupt from the soundcard. | The driver, sound.obj will do this when it gets an interrupt from the soundcard. | ||
Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event. | Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event. | ||
It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other. | It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other. | ||
In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard. | In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard. | ||
Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity. | Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity. | ||
(I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets). | (I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets). | ||
<asm> | <syntaxhighlight lang="asm"> | ||
align 4 | align 4 | ||
proc hda_irq ;+ | proc hda_irq ;+ | ||
Line 56: | Line 56: | ||
cmp [ctrl.user_callback], 0 | cmp [ctrl.user_callback], 0 | ||
je @f | je @f | ||
stdcall [ctrl.user_callback], ebx | stdcall [ctrl.user_callback], ebx | ||
;!!!!!!!!!!! ] | ;!!!!!!!!!!! ] | ||
@@: | @@: | ||
Line 78: | Line 78: | ||
ret | ret | ||
endp | endp | ||
</ | </syntaxhighlight> | ||
Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity. | Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity. | ||
Every buffer has to be page aligned and be exactly 16Kbytes. | Every buffer has to be page aligned and be exactly 16Kbytes. | ||
So for two buffers we would have: | So for two buffers we would have: | ||
<asm> | <syntaxhighlight lang="asm"> | ||
stdcall KernelAlloc, 0x8000 | stdcall KernelAlloc, 0x8000 | ||
mov [ctrl.buffer], eax | mov [ctrl.buffer], eax | ||
Line 95: | Line 95: | ||
cld | cld | ||
rep stosd | rep stosd | ||
</ | </syntaxhighlight> | ||
Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it. | Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it. | ||
All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj). | All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj). | ||
This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard. | This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard. | ||
[[Category:Coding]] | [[Category:Coding]] |
Latest revision as of 12:46, 22 April 2012
Intro
Layers
An application wich wants to output sound has to:
- create a buffer using the SND_CREATE_BUFF service routine of Infinity.
- Set the format of the buffer using the SND_SET_FORMAT service routine of Infinity.
- Start playing using the SND_PLAY service routine of Infinity.
- Update the sound samples in the buffer.
Infinity gets the samples from all sound buffers of all applications that output sound and mixes them together in one buffer wich is then send to sound.obj.
When Infinity is called for the first time, it inits itself and then calls sound.obj wich also initialises. Infinity calls the DEV_CALLBACK service routine of sound.obj to insert the address of the callback function to the [ctrl.user_callback] variable. Sound.obj is responsible for calling this callback function every time the buffers need to be refilled. The driver, sound.obj will do this when it gets an interrupt from the soundcard. Before doing this, the interrupt handler should check to see if the interrupt was generated because of an 'end of buffer' event. It is possible that there are multiple, e.g. 2, buffers (like in HDA) wich sound.obj needs to fill, one after the other. In this case, one buffer is given to Infinity to refill it with new portion of samples, while the second is being outputed by souncard.
Here is an example HDA IRQ handler, where you can see the piece of code that changes buffers and calls the callback function of Infinity. (I have selected that piece by ;!!!!!!!!!!! [ .... ;!!!!!!!!!!! ] brackets).
align 4
proc hda_irq ;+
; if DEBUG_IRQ
; mov esi, msgIRQ
; call SysMsgBoardStr
; end if
mov edx, ICH6_REG_INTSTS
call azx_readl
test eax, eax
jnz @f
popa
ret
@@:
;!!!!!!!!!!! [
mov ebx, eax ; status
mov eax, 1 shl 4
test ebx, eax
jz @f
mov al, SD_INT_MASK
mov edx, ICH6_REG_SD_STS + SDO0_SD_OFFSET
call azx_writeb
mov eax, [civ_val]
inc eax
and eax, 1
mov [civ_val], eax
mov ebx, dword [buff_list+eax*4]
cmp [ctrl.user_callback], 0
je @f
stdcall [ctrl.user_callback], ebx
;!!!!!!!!!!! ]
@@:
; clear rirb int
mov edx, ICH6_REG_RIRBSTS
call azx_readb
test al, RIRB_INT_MASK
jz .l1
test al, RIRB_INT_RESPONSE
jz @f
call azx_update_rirb
@@:
mov al, RIRB_INT_MASK
mov edx, ICH6_REG_RIRBSTS
call azx_writeb
.l1:
ret
endp
Sound.obj is also responsible for creating the sound buffers that will be read by souncard and filled in by Infinity.
Every buffer has to be page aligned and be exactly 16Kbytes.
So for two buffers we would have:
stdcall KernelAlloc, 0x8000
mov [ctrl.buffer], eax
mov edi, eax
mov ecx, 0x8000/4
xor eax, eax
cld
rep stosd
Infinity does not need to know how the sound is outputed to the sound card, it is the matter of sound.obj to operate with it. All that Infinity has to know is address of the sound buffer and when to fill it (all this information is given to it by sound.obj). This approach gives us HAL (hardware abstraction layer) wich makes the KolibriOS sound system universal and usefull for any soundcard.