Ну, наверно вы не проверили свой код. Тот же результат.
Ну, наверно вы не проверили свой код. Тот же результат.
Сомневаюсь, и вам советую!
Ну я подготовил фрейм, проиграл отрывок, пошел следующий готовить. Так вот при любом раскладе получается как в том отрывке, что я приводил - по сути бесконечный цикл с паузой только на проигрывание отрывка. Вот тут и получается, что каким бы методом я не ждал - вашим или своим (из MSDN), я получаю щелчок.
Сомневаюсь, и вам советую!
Я так и подозревал, но пока с синхронизацией не очень. По сути получается, что не дожидаясь окончания проигрывания первого куска ставить на проигрывание второй, и только на третьем ждать пока выпадет из очереди первый, после чего и третий ставить. Наверно так.
Сомневаюсь, и вам советую!
Алгоритм такой же, как и при работе с двумя спековскими экранами.
10 создать event
20 открыть устройство
30 создать и инициализировать буфер1
40 создать и инициализировать буфер2
50 курсор=буфер1
60 ждем пока освободится *курсор
70 пишем в *курсор
80 отправляем *курсор на воспроизведение
90 если курсор=буфер1, то курсор=буфер2, иначе курсор=буфер1
100 если не завершили переход на 60
110 закрыть устройство
120 освободить буфер1
130 освободить буфер2
140 освободить event
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
Кусочек из AY эмулятора на PureBasic отвечающий за вывод звука:
PHP код:
; ----------------------------------------------
; Public functions
; ----------------------------------------------
Declare.l Sound_Start()
Declare.l Sound_Stop()
Declare.l Sound_SetCallbacks(adressReset.l, adressSample.l, adressUpdate.l, adressTick.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 / 8 * 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 << 2 ) << 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.l = 0
Global Sound_SampleMax.l = Sound_MixRate / 50
Global Sound_WaveHdr.WAVEHDR
Global Sound_WaveOutHandle.l = 0
Global Sound_Software_Exit.l = #False
Global Sound_Software_ThreadFinished.l = #False
Global Sound_Software_Thread.l = 0
Global Sound_Software_FillBlock.l = 0
Global Sound_Software_RealBlock.l = 0
Global Sound_Software_UpdateMutex.l = #False
Global Sound_CallbackReset.l = 0
Global Sound_CallbackSample.l = 0
Global Sound_CallbackTick.l = 0
Global Sound_CallbackUpdate.l = 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.l = 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_WaveHdr, SizeOf(WAVEHDR))
Debug_ ("waveOutPrepareHeader "+Str(res))
If res<>0
ProcedureReturn 2
EndIf
res = waveOutWrite_(Sound_WaveOutHandle, @Sound_WaveHdr, SizeOf(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_Thread, 32) ; 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_WaveHdr, SizeOf(WAVEHDR))
Debug_ ("waveOutUnprepareHeader "+Str(res))
Debug_ ("WHDR_DONE flag " + Str( Sound_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.l, adressSample.l, adressUpdate.l, adressTick.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, @mmt, SizeOf(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
Если у нас есть 71680 тактов на кадр, 882 куска звука, то получается нам надо рендерить каждые 81.26 тактов.
Ну с AY пока абы что, но это понятно, только понял как оно работает. Но вот спикер - девайс простейший. Ни волны, ни плавных уровней. Сразу же заработало. Диззик прекрасно пищит, прям как на реале. Чудесно.
Но вот дальше тупичок. Почему-то простой клавиатурный "пук" не слышен. Там нет никаких хитростей?
Сомневаюсь, и вам советую!
ZXMAK2 - Виртуальная Машина ZX Spectrum https://github.com/zxmak/ZXMAK2 (старая ссылка http://zxmak2.codeplex.com)
ZXMAK.NET - спектрум на C# http://sourceforge.net/projects/zxmak-dotnet
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)