Code: Select all
Enumeration
#Window
#Play
#Play6000
EndEnumeration
DataSection
StartVGMFile:
IncludeBinary "E:\SHORT.vgm"
EndOfVGMFile:
EndDataSection
OPNhdll = OpenLibrary(0, "OPN_DLL.dll")
If OPNhdll
Prototype OpenDriver(int.i)
Prototype CloseDriver()
Prototype OPNWrite(int.i,int2.i,int3.i)
Prototype OPNPlayDACSample(chip.i, size.i, *Data, freq.i)
Global OpenOPNDriver.OpenDriver = GetFunction(0, "OpenOPNDriver")
Global CloseOPNDriver.CloseDriver = GetFunction(0, "CloseOPNDriver")
Global OPN_Write.OPNWrite = GetFunction(0, "OPN_Write")
Global PlayDACSample.OPNPlayDACSample = GetFunction(0, "PlayDACSample")
Else
;error
End
EndIf
Structure VGMFSt
type.i
reg.a
val.a
pause.u
samplenum.a
sampleadress.i
samplesize.i
summofpauses.i
EndStructure
Global Dim VGMARR.VGMFSt(0)
Global autofreq = 1
; shutdown sound procedure when track is done, or stop by button
Procedure EndOfPlay(sh.i)
OPN_Write(0, $2B, $00) ; Disable Dac
; probably RR param need to high level for shutdown
OPN_Write(0, $80 + sh, $0F)
OPN_Write(0, $81 + sh, $0F)
OPN_Write(0, $82 + sh, $0F)
OPN_Write(0, $84 + sh, $0F)
OPN_Write(0, $85 + sh, $0F)
OPN_Write(0, $86 + sh, $0F)
OPN_Write(0, $88 + sh, $0F)
OPN_Write(0, $89 + sh, $0F)
OPN_Write(0, $8A + sh, $0F)
OPN_Write(0, $8C + sh, $0F)
OPN_Write(0, $8D + sh, $0F)
OPN_Write(0, $8E + sh, $0F)
If sh = 0
OPN_Write(0, $28, $00) ; turn off
OPN_Write(0, $28, $01)
OPN_Write(0, $28, $02)
Else
OPN_Write(0, $28, $04)
OPN_Write(0, $28, $05)
OPN_Write(0, $28, $06)
EndIf
EndProcedure
; procedure work in another thread
Procedure ReadAndPlay(*Value)
;get vgm adress without head
ot = ?StartVGMFile + 64
do = ?EndOfVGMFile
; reset main array
Dim VGMARR(0)
Number.a = 0
WavAddres = 0
Arrayind = 0
samplecoordinates = -1
; cycle of reading
For i = ot To do
; Reads an ascii character (1 byte) from the specified memory address.
Number = PeekA(i)
Select Number
Case $67 ; wav data block adress
; Reads an integer (4 bytes in 32-bit executable, 8 bytes in 64-bit executable) number from the specified memory address.
WavDataSize = PeekI(i + 3)
; get this adress in mem
WavAddres = i + 7
; jump reads to end of wav data block
i + 6 + WavDataSize
Case $52
VGMARR(Arrayind)\type = 1
VGMARR(Arrayind)\reg = PeekA(i+1) ; get register
VGMARR(Arrayind)\val = PeekA(i+2) ; get value of register
; temporaly make ignore $2A. maybe somewhen i fix it to right
If VGMARR(Arrayind)\reg <> $2A
Arrayind + 1
ReDim VGMARR(Arrayind) ; +1 to array size
EndIf
i+2 ; make jump to next pointer
Case $53
VGMARR(Arrayind)\type = 2
VGMARR(Arrayind)\reg = PeekA(i+1)
VGMARR(Arrayind)\val = PeekA(i+2)
Arrayind + 1
ReDim VGMARR(Arrayind)
i+2
Case $61 ; $61 - can range from 0 to 65535 (approx 1.49 seconds)
VGMARR(Arrayind)\type = 3
VGMARR(Arrayind)\pause = PeekU(i + 1)
; it is not very correct... but if i will have working $2A - it will no need this.
If flagpausehunt
VGMARR(numforsizecount)\summofpauses + VGMARR(Arrayind)\pause
flagpausehunt = 0
EndIf
Arrayind + 1
ReDim VGMARR(Arrayind)
i+2
Case $70 To $7F ; wait n+1 samples, n can range from 0 to 15.
VGMARR(Arrayind)\type = 3
VGMARR(Arrayind)\pause = ((Number - $70) + 1)
If flagpausehunt
VGMARR(numforsizecount)\summofpauses + VGMARR(Arrayind)\pause
flagpausehunt = 0
EndIf
Arrayind + 1
ReDim VGMARR(Arrayind)
Case $E0 ; 0xE0 dddddddd seek to offset dddddddd (Intel byte order) in PCM data bank
; prepear adress for next 0x8n
samplecoordinates = PeekI(i + 1)
samplecoordinates = WavAddres + samplecoordinates
; jump to next command
i + 4
Case $80 To $8F
If samplecoordinates > -1
VGMARR(Arrayind)\type = 4
VGMARR(Arrayind)\sampleadress = samplecoordinates
VGMARR(Arrayind)\summofpauses = 0
numforsizecount = Arrayind ; remember array position for count size and freq
Arrayind + 1
ReDim VGMARR(Arrayind)
samplecoordinates = -1 ; no need more, just for once work per sample
EndIf
; start collect size per each 0x8n
VGMARR(numforsizecount)\samplesize = VGMARR(numforsizecount)\samplesize + 1
flagpausehunt = 1 ; flag for start collect pauses too
; get n - as pause, and remember it, if exists
If Number > $80
VGMARR(Arrayind)\type = 3
VGMARR(Arrayind)\pause = (Number - $80)
VGMARR(numforsizecount)\summofpauses + VGMARR(Arrayind)\pause
Arrayind + 1
ReDim VGMARR(Arrayind)
EndIf
Case $4F ; 0x4F dd Game Gear PSG stereo, write dd to port 0x06 ; dune with samples
; ignore until ValleyBell add support SN76489/SN76496 to OPN.dll :)))))))
i + 1
Case $50 ; 0x50 dd PSG (SN76489/SN76496) write value dd ; dune with samples
; again ignore and jump far
i + 1
Case $62 ; wait 735 samples (60th of a second), a shortcut for 0x61 0xdf 0x02 ; Lego Tune
VGMARR(Arrayind)\type = 3
VGMARR(Arrayind)\pause = 735
If flagpausehunt
VGMARR(numforsizecount)\summofpauses + VGMARR(Arrayind)\pause
flagpausehunt = 0
EndIf
Arrayind + 1
ReDim VGMARR(Arrayind)
Case $63 ; wait 882 samples (50th of a second), a shortcut For 0x61 0x72 0x03
VGMARR(Arrayind)\type = 3
VGMARR(Arrayind)\pause = 882
If flagpausehunt
VGMARR(numforsizecount)\summofpauses + VGMARR(Arrayind)\pause
flagpausehunt = 0
EndIf
Arrayind + 1
ReDim VGMARR(Arrayind)
Case $66 ; end of sound
Break
EndSelect
Next
; it is for organization of pauses less, than millisec
PlayedTicks.i = 0
PlayedUS.i = 0
CurrentUS.i = 0
StartMS.i = ElapsedMilliseconds()
; cycle of playing
For i = 0 To ArraySize(VGMARR())-1
Select VGMARR(i)\type
Case 1
OPN_Write(0, VGMARR(i)\reg, VGMARR(i)\val)
Case 2
; probably cpu have some command with $53, but no need +256... now i set for all +256
tmp = VGMARR(i)\reg+256
OPN_Write(0, tmp, VGMARR(i)\val)
Case 3
; that cursed pause...
PlayedTicks + VGMARR(i)\pause
PlayedUS = PlayedTicks * 22.675736961 ;(this 22 - As 1s/44100hz. and 22 it means microsec)
While (CurrentUS < PlayedUS)
Delay(1)
CurrentUS.i = (ElapsedMilliseconds() - StartMS) * 1000
Wend
Case 4
If autofreq = 1
; count frequency
freq = VGMARR(i)\samplesize / (VGMARR(i)\summofpauses * 0.000022675736961)
PlayDACSample(0, VGMARR(i)\samplesize, VGMARR(i)\sampleadress, freq)
Else
PlayDACSample(0, VGMARR(i)\samplesize, VGMARR(i)\sampleadress, 6000)
EndIf
EndSelect
Next
; shutdown of sound
EndOfPlay(0)
EndOfPlay(256)
; enable plays button
DisableGadget(#Play, 0)
DisableGadget(#Play6000, 0)
EndProcedure
OpenOPNDriver(1)
If OpenWindow(#Window, 100, 100, 300, 100, "play", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
ButtonGadget(#Play, 10, 10, 200, 30, "play auto freq")
ButtonGadget(#Play6000, 10, 50, 200, 30, "play 6k freq")
OPN_Write(0, $2B, $80)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #Play
DisableGadget(#Play, 1) ; disable for avoid double press button
DisableGadget(#Play6000, 1)
autofreq = 1
CreateThread(@ReadAndPlay(), 1)
Case #Play6000
DisableGadget(#Play, 1)
DisableGadget(#Play6000, 1)
autofreq = 0
CreateThread(@ReadAndPlay(), 1)
EndSelect
Case #PB_Event_CloseWindow
stopflag = 1
Quit = 1
EndSelect
Until Quit = 1
CloseOPNDriver()
CloseLibrary(0)
EndIf
and attach exe file. lesson third snare! by VGM it is kick + snare doubled sample as one. but this second part PlayDac is eat. and eat when 10k or 12k. when 6k - no eat and PlayDac work fine. so it means PlayDac have some cache... with 10k PlayDac work very fast and this cache is ends. with 6k this cache not depleted and play is continue after DAC Disable and Enable.
ops... attach not want to sends.