Кусочек из AY эмулятора на PureBasic отвечающий за вывод звука:

PHP код:



; ----------------------------------------------
;   Public 
functions
; ----------------------------------------------

Declare.
l Sound_Start()
Declare.
l Sound_Stop()
Declare.
l Sound_SetCallbacks(adressReset.ladressSample.ladressUpdate.ladressTick.l)
Declare.
l Sound_SetCallbackReset(adress.l)
Declare.
l Sound_GetCallbackReset()
Declare.
l Sound_SetCallbackSample(adress.l)
Declare.
l Sound_GetCallbackSample()
Declare.
l Sound_SetCallbackTick(adress.l)
Declare.
l Sound_GetCallbackTick()
Declare.
l Sound_SetCallbackUpdate(adress.l)
Declare.
l Sound_GetCallbackUpdate()



; ----------------------------------------------
;   Private 
functions
; ----------------------------------------------

Declare.
l Sound_Software_Fill()
Declare.
l Sound_Software_DoubleBufferThread(value.l)
Declare.
l Sound_ClearBuffer()

; ----------------------------------------------
;   Private 
vars
; ----------------------------------------------

;- 
Vars

#Sound_LATENCY = 20
#Sound_SLEEPTIME = 4
    
Global Sound_BufferSizeMs.l            1000
Global Sound_Channels.l                2
Global Sound_Bits.l                16
Global Sound_Bytes.l                Sound_Bits Sound_Channels
Global Sound_MixRate.l                44100
Global Sound_BlockSize.l            = ((Sound_MixRate #Sound_LATENCY / 1000) + 3) & $FFFFFFFC                ;    // Number of *samples*
Global Sound_BufferSize.l            = ( Sound_BlockSize << ) << 1                                     ;( Sound_BlockSize * (Sound_BufferSizeMs #Sound_LATENCY) ) << 1        ;    // make it perfectly divisible by granularity - double buffer
Global Sound_TotalBlocks.l            Sound_BufferSize Sound_BlockSize
Global Sound_BufferMemoryLength.l        Sound_BufferSize Sound_Bytes        ;// 16bits
Global Sound_BufferMemory.l            0

Global Sound_SampleCount.0                            
Global Sound_SampleMax.Sound_MixRate 50            

Global Sound_WaveHdr.WAVEHDR                
Global Sound_WaveOutHandle.0                

Global Sound_Software_Exit.#False                
Global Sound_Software_ThreadFinished.#False            
Global Sound_Software_Thread.0                    

Global Sound_Software_FillBlock.0
Global Sound_Software_RealBlock.0
Global Sound_Software_UpdateMutex.#False

Global Sound_CallbackReset.0                    
Global Sound_CallbackSample.0                    
Global Sound_CallbackTick.0
Global Sound_CallbackUpdate.0            

Debug_
("Sound_Bytes "+Str(Sound_Bytes))
Debug_("Sound_BlockSize "+Str(Sound_BlockSize))
Debug_("Sound_BufferSize "+Str(Sound_BufferSize))
Debug_("Sound_TotalBlocks "+Str(Sound_TotalBlocks))
Debug_("Sound_BufferMemoryLength "+Str(Sound_BufferMemoryLength))
Debug_("Sound_SampleMax "+Str(Sound_SampleMax))
Debug_("")



;- 
Procedures

Procedure
.l Sound_Software_Fill()
    Protected 
i.l
    
Protected mixpos.l
    
Protected mixBuffer.l
    
    mixpos 
Sound_Software_FillBlock Sound_BlockSize
    mixBuffer 
Sound_BufferMemory mixpos Sound_Bytes
    
     
Debug_Str(Sound_Software_FillBlock)+" "+Str(mixBuffer) )

    For 
i=0 To Sound_BlockSize-1        
        
If Sound_CallbackSample<>0  :  CallFunctionFast(Sound_CallbackSample,mixBuffer)  :  EndIf
        
        
Sound_SampleCount+1
        
If Sound_SampleCount Sound_SampleMax
            
If Sound_CallbackTick<>0  :  CallFunctionFast(Sound_CallbackTick)  :  EndIf
            
Sound_SampleCount=0
        
EndIf
    
        
mixBuffer Sound_Bytes
    Next

    Sound_Software_FillBlock 
1
    
If Sound_Software_FillBlock >= Sound_TotalBlocks 
        Sound_Software_FillBlock 
0
    
EndIf
EndProcedure

Procedure
.l Sound_CreateBuffer()
    If 
Sound_BufferMemory=0
        Sound_BufferMemory 
AllocateMemory(Sound_BufferMemoryLength)
    EndIf
EndProcedure

Procedure
.l Sound_FreeBuffer()
    If 
Sound_BufferMemory<>0
        
FreeMemory(Sound_BufferMemory)
        
Sound_BufferMemory 0
    
EndIf
EndProcedure

Procedure
.l Sound_ClearBuffer()
    For 
i=0 To Sound_BufferMemoryLength-1
        PokeL 
(Sound_BufferMemory+i,0)
    
Next
EndProcedure

Procedure
.l Sound_Start()
    Protected 
i.l
    
Protected res.l
    
Protected pcmwf.WAVEFORMATEX
    
    Debug_ 
("Sound start")
    
    If 
Sound_CallbackReset<>0  :  CallFunctionFast(Sound_CallbackReset)  :  EndIf
    
Sound_CreateBuffer()
    
Sound_ClearBuffer()
    
    
Sound_WaveOutHandle 0
    
    pcmwf
\wFormatTag        #WAVE_FORMAT_PCM
    
pcmwf\nChannels            Sound_Channels
    pcmwf
\wBitsPerSample    Sound_Bits
    pcmwf
\nBlockAlign        Sound_Bytes
    pcmwf
\nSamplesPerSec    Sound_MixRate
    pcmwf
\nAvgBytesPerSec    Sound_MixRate Sound_Bytes
    pcmwf
\cbSize            0
    
    res
.waveOutOpen_( @Sound_WaveOutHandle#WAVE_MAPPER, @pcmwf, 0, 0, 0)
    
Debug_ ("waveOutOpen "+Str(res))
    
Debug_ ("waveOutHandle "+Str(Sound_WaveOutHandle))
    
    If 
res<>0
        ProcedureReturn 1
    
EndIf
        
    
Sound_WaveHdr\dwFlags            #WHDR_BEGINLOOP | #WHDR_ENDLOOP
    
Sound_WaveHdr\lpData            Sound_BufferMemory                ;Sound_Memory_Calloc(length);
    
Sound_WaveHdr\dwBufferLength    Sound_BufferMemoryLength
    Sound_WaveHdr
\dwBytesRecorded    0
    Sound_WaveHdr
\dwUser            0
    Sound_WaveHdr
\dwLoops            = -1
    Sound_WaveHdr
\lpNext            0
    
    res 
waveOutPrepareHeader_(Sound_WaveOutHandle, @Sound_WaveHdrSizeOf(WAVEHDR))
    
Debug_ ("waveOutPrepareHeader "+Str(res))
    
    If 
res<>0
        ProcedureReturn 2
    
EndIf
    
    
res waveOutWrite_(Sound_WaveOutHandle, @Sound_WaveHdrSizeOf(WAVEHDR))
    
Debug_ ("waveOutWrite "+Str(res))
    
    If 
res<>0
        ProcedureReturn 3
    
EndIf

    
Sound_Software_FillBlock 0
    Sound_Software_RealBlock 
0
    Sound_Software_UpdateMutex 
#False
    
Sound_SampleCount 0
    Sound_Software_Exit 
#False
    
    
Debug_ ("Create thread")
    
    
timeBeginPeriod_(1)
    
Sound_Software_Thread CreateThread(@Sound_Software_DoubleBufferThread(), 0)
    
ThreadPriority(Sound_Software_Thread32)                                            ; THREAD_PRIORITY_TIME_CRITICAL)
    
    
Debug_ ("")
    
    
ProcedureReturn 0
EndProcedure

Procedure
.l Sound_Stop()

    
Debug_("Sound stop")

    ; 
kill Thread
    Sound_Software_Exit 
#True
    
While Not Sound_Software_ThreadFinished
        Debug_ 
("Wait thread")
        
Sleep_(10)
    
Wend
    Sound_Software_Thread 
0
    Debug_
("Kill thread")

    
res waveOutReset_(Sound_WaveOutHandle)
    
Debug_ ("waveOutReset "+Str(res)) 
    
    
res waveOutUnprepareHeader_(Sound_WaveOutHandle, @Sound_WaveHdrSizeOf(WAVEHDR))
    
Debug_ ("waveOutUnprepareHeader "+Str(res))
    
    
Debug_ ("WHDR_DONE flag " StrSound_WaveHdr\dwFlags #WHDR_DONE ))    

    
res waveOutClose_(Sound_WaveOutHandle)
    
Debug_ ("waveOutClose "+Str(res))
    
    
Sound_FreeBuffer()
    
    
ProcedureReturn 0 
EndProcedure

Procedure
.l Sound_SetCallbackReset(adress.l)
    If 
adress<>0
        Sound_CallbackReset 
adress
        ProcedureReturn 1
    
Else
        
ProcedureReturn 0
    
EndIf
EndProcedure

Procedure
.l Sound_GetCallbackReset()
    
ProcedureReturn Sound_CallbackReset
EndProcedure

Procedure
.l Sound_SetCallbackSample(adress.l)
    If 
adress<>0
        Sound_CallbackSample 
adress
        ProcedureReturn 1
    
Else
        
ProcedureReturn 0
    
EndIf
EndProcedure

Procedure
.l Sound_GetCallbackSample()
    
ProcedureReturn Sound_CallbackSample
EndProcedure

Procedure
.l Sound_SetCallbackTick(adress.l)
    If 
adress<>0
        Sound_CallbackTick 
adress
        ProcedureReturn 1
    
Else
        
ProcedureReturn 0
    
EndIf
EndProcedure

Procedure
.l Sound_GetCallbackTick()
    
ProcedureReturn Sound_CallbackTick
EndProcedure

Procedure
.l Sound_SetCallbackUpdate(adress.l)
    If 
adress<>0
        Sound_CallbackUpdate 
adress
        ProcedureReturn 1
    
Else
        
ProcedureReturn 0
    
EndIf
EndProcedure

Procedure
.l Sound_GetCallbackUpdate()
    
ProcedureReturn Sound_CallbackUpdate
EndProcedure

Procedure
.l Sound_SetCallbacks(adressReset.ladressSample.ladressUpdate.ladressTick.l)
    
Sound_SetCallbackReset (adressReset)
    
Sound_SetCallbackSample (adressSample)
    
Sound_SetCallbackTick (adressTick)
    
Sound_SetCallbackUpdate (adressUpdate)
EndProcedure

Procedure
.l Sound_Software_DoubleBufferThread(value.l)
    Protected 
mmt.MMTIME
    
Protected cursorpos.l
    
Protected cursorblock.l
    
Protected prevblock.l    
    
    
;Debug_ ("Thread Started")
    
Sound_Software_ThreadFinished #False    
    
    
While Not Sound_Software_Exit

         mmt
\wType #TIME_BYTES
         
waveOutGetPosition_(Sound_WaveOutHandle, @mmtSizeOf(MMTIME))
         
cursorpos mmt\u\cb >> 2
         cursorpos 
Sound_BufferSize         
         cursorblock 
cursorpos Sound_BlockSize
         
         
;Debug_(Str(cursorpos)+" "+Str(cursorblock)+" "+Str(Sound_Software_FillBlock))

        
prevblock cursorblock 1
        
If prevblock 0
            prevblock 
Sound_TotalBlocks  1
        
EndIf

         While 
Sound_Software_FillBlock <> cursorblock
             Sound_Software_UpdateMutex 
#True
             
Sound_Software_Fill()
             
Sound_Software_RealBlock+1
             
If Sound_Software_RealBlock >= Sound_TotalBlocks 
                 Sound_Software_RealBlock 
0
            
EndIf
            
Sound_Software_UpdateMutex #False
        
Wend
        
        
If Sound_CallbackUpdate<>0  :  CallFunctionFast(Sound_CallbackUpdate)  :  EndIf
        
        
Sleep_(#Sound_SLEEPTIME)
    
Wend
    
;Debug_ ("Thread Finished")
    
Sound_Software_ThreadFinished #True
EndProcedure