this array is suks... some times i make overlimit and crash. and i am still not make noise type, and i have no idea how to make work it for 4 channels...
no need to load, just play. and you can change some switchers for different effect of playing.
Code: Select all
Enumeration
#Window
#Gadget
#Gadget2
#Img01
#Img02
#AtRP
#AtRG
#AtRM
#AtLP
#AtLG
#AtLM
#DcRP
#DcRG
#DcRM
#SyLP
#SyLG
#SyLM
#RrRP
#RrRG
#RrRM
#Load
EndEnumeration
XIncludeFile "G:\DISTR\SEREGASOFT\MIDI\SN76489 module.pb"
Global type
Global noisedata
Global attackrate
Global sustainlevel
Global attacklevel
Global decayrate
Global releaserate
Global psgstart ; means duration
Global psgmarker
Global PhaseOfPSG
Global curvolume = 17
Global Dim PSGnote.i($5F)
For i = 0 To $21
PSGnote(i) = 1017
Next
;PSGnote($20) = 1017
;PSGnote($21) = 1017
PSGnote($22) = 960
PSGnote($23) = 906
PSGnote($24) = 855
PSGnote($25) = 807
PSGnote($26) = 762
PSGnote($27) = 719
PSGnote($28) = 679
PSGnote($29) = 641
PSGnote($2A) = 605
PSGnote($2B) = 571
PSGnote($2C) = 539
PSGnote($2D) = 508
PSGnote($2E) = 480
PSGnote($2F) = 453
PSGnote($30) = 428
PSGnote($31) = 404
PSGnote($32) = 381
PSGnote($33) = 360
PSGnote($34) = 339
PSGnote($35) = 320
PSGnote($36) = 302
PSGnote($37) = 285
PSGnote($38) = 269
PSGnote($39) = 254
PSGnote($3A) = 240
PSGnote($3B) = 226
PSGnote($3C) = 214
PSGnote($3D) = 202
PSGnote($3E) = 190
PSGnote($3F) = 180
PSGnote($40) = 170
PSGnote($41) = 160
PSGnote($42) = 151
PSGnote($43) = 143
PSGnote($44) = 135
PSGnote($45) = 127
PSGnote($46) = 120
PSGnote($47) = 113
PSGnote($48) = 107
PSGnote($49) = 101
PSGnote($4A) = 95
PSGnote($4B) = 90
PSGnote($4C) = 85
PSGnote($4D) = 80
PSGnote($4E) = 76
PSGnote($4F) = 71
PSGnote($50) = 67
PSGnote($51) = 64
PSGnote($52) = 60
PSGnote($53) = 57
PSGnote($54) = 53
PSGnote($55) = 50
PSGnote($56) = 47
PSGnote($57) = 45
PSGnote($58) = 42
PSGnote($59) = 40
PSGnote($5A) = 38
PSGnote($5B) = 35
PSGnote($5C) = 33
PSGnote($5D) = 32
PSGnote($5E) = 30
PSGnote($5F) = 28
Global Dim PSGInstrActionsKeyOn.i(1)
Global Dim PSGInstrActionsKeyOff.i(0)
Global Dim PSGInstARValues(0) ; Attack Rate
Global Dim PSGInstDRValues(0) ; Decoy Rate
Global Dim PSGInstRRValues(0) ; Relise Rate
;{
Macro SetBit(Var, Bit)
Var | (Bit)
EndMacro
Macro ClearBit(Var, Bit)
Var & (~(Bit))
EndMacro
Macro TestBit(Var, Bit)
Bool(Var & (Bit))
EndMacro
Macro NumToBit(Num)
(1<<(Num))
EndMacro
Macro GetBits(Var, StartPos, EndPos)
((Var>>(StartPos))&(NumToBit((EndPos)-(StartPos)+1)-1))
EndMacro
;}
Procedure FillARarray(ARvalue.i, ALvalue.i)
ReDim PSGInstARValues(0)
If ARvalue = $FF Or ARvalue = 32; 0 AR, top volume immediatly
PSGInstARValues(0) = ALvalue
Else
counterd.d = 255 / (ARvalue * 16)
countershift.d = counterd
For i = 15 To ALvalue Step -1
counteri = Int(countershift)
If counteri > 0
startnumarray = ArraySize(PSGInstARValues())
ReDim PSGInstARValues(startnumarray + counteri)
For k = startnumarray To startnumarray + counteri
PSGInstARValues(k) = i
Next
EndIf
countershift = countershift - counteri ; get 0.x value
countershift + counterd ; 0.x + how it names...
Next
EndIf
EndProcedure
Procedure FillDRarray(DRvalue.i, ALvalue.i, SLvalue.i)
ReDim PSGInstDRValues(0)
If DRvalue = 32 ; Sustain Level volume immedeatly
PSGInstDRValues(0) = SLvalue
Else
counterd.d = 255 / (DRvalue * 16)
countershift.d = counterd
summoftik = SLvalue - ALvalue
tmpval = ALvalue
If summoftik < 0
summoftik = ALvalue - SLvalue
tmpval = SLvalue
EndIf
For i = 0 To summoftik
counteri = Int(countershift)
If counteri > 0
startnumarray = ArraySize(PSGInstDRValues())
ReDim PSGInstDRValues(startnumarray + counteri)
For k = startnumarray To startnumarray + counteri
PSGInstDRValues(k) = tmpval + i
Next
EndIf
countershift = countershift - counteri
countershift + counterd
Next
EndIf
EndProcedure
Procedure FillRRarray(RRvalue.i)
ReDim PSGInstRRValues(0)
If RRvalue = 32 ; silence immediatly
PSGInstRRValues(0) = 15
Else
counterd.d = 255 / (RRvalue * 16)
countershift.d = counterd
For i = 0 To 15
counteri = Int(countershift)
If counteri > 0
startnumarray = ArraySize(PSGInstRRValues())
ReDim PSGInstRRValues(startnumarray + counteri)
For k = startnumarray To startnumarray + counteri
PSGInstRRValues(k) = i
Next
EndIf
countershift = countershift - counteri
countershift + counterd
Next
EndIf
EndProcedure
Procedure PaintSin(volume)
GrabImage(#Img01, #Img02, 1, 0, 279, 70)
CopyImage(#Img02, #Img01)
If StartDrawing(ImageOutput(#Img01))
Plot(278, (volume * 4)+4, RGB(0, 200, 0))
StopDrawing()
SetGadgetState(#Gadget2, ImageID(#Img01))
EndIf
EndProcedure
Procedure PSGPlay(*Value)
Repeat
If psgstart > 0
;1. Attack Phase [volume up With Attack Rate until Attack Level],
;2. Decay Phase [volume down With Decay Rate until Sustain Level],
;3. Sustain Phase [volume down With SustainRate Until 0]
;actually... no, the Sustain Rate is fixed To 0 in GEMS, so the volume
;stays at its level there.
;Anywhere in this, a "Key Off" breaks into the
;4. Release Phase [volume down With Release Rate Until 0]
;With "volume 0" I mean "silence" here, so For the PSG it's actually value $F
;frequency is sets. i means instrument is rule of volume in a time
;get position of sound playing
tmppsgmarker = psgmarker - psgstart
Select PhaseOfPSG
Case 0 ; Attack Rate
;check when phase is ends
;Debug tmppsgmarker
If PSGInstARValues(tmppsgmarker) <= attacklevel
PhaseOfPSG = 1
startdecaytik = tmppsgmarker + 1
;set volume
;%1001000
Write(144 + attacklevel)
curvolume = attacklevel
Else
;set volume
;%1001000
Write(144 + PSGInstARValues(tmppsgmarker))
curvolume = PSGInstARValues(tmppsgmarker)
EndIf
Case 1 ; Decay Rate
;check when phase is ends
If PSGInstDRValues(tmppsgmarker - startdecaytik) >= sustainlevel
PhaseOfPSG = 2
startreliserate = tmppsgmarker
;set volume
;%1001000
Write(144 + sustainlevel)
curvolume = sustainlevel
Else
;set volume
;%1001000
Write(144 + PSGInstDRValues(tmppsgmarker - startdecaytik))
curvolume = PSGInstDRValues(tmppsgmarker - startdecaytik)
EndIf
EndSelect
PaintSin(curvolume)
psgstart - 1
Else
;start ReliseRate - Fade out
If curvolume < 15
;Debug "RR"
For i = 0 To ArraySize(PSGInstRRValues())
;get array tik
If PSGInstRRValues(i) >= curvolume
startfadeout = i
Write(144 + PSGInstRRValues(i))
PaintSin(PSGInstRRValues(i))
Break
EndIf
Next
curvolume = 16
ElseIf curvolume = 16
If startfadeout <= ArraySize(PSGInstRRValues())
Write(144 + PSGInstRRValues(startfadeout))
PaintSin(PSGInstRRValues(startfadeout))
If PSGInstRRValues(startfadeout) = 15
curvolume = 17 ; stop RR work
EndIf
startfadeout + 1
EndIf
EndIf
EndIf
;Delay(80) ; let's image it as gems's delay 1.
; but, as test shows, it cant be delay 1, but 1/60sec
Delay(17) ; 16.66666.... let it be 17
ForEver
EndProcedure
;FillARarray($1B, 0)
;FillARarray($1F, 0)
;FillARarray($0A, 0)
;For i = 0 To ArraySize(PSGInstARValues())
; text$ + " " + Str(PSGInstARValues(i))
;Next
;Debug "; " + text$
;FillDRarray($0A, 15)
;For i = 0 To ArraySize(PSGInstDRValues())
; text$ + " " + Str(PSGInstDRValues(i))
;Next
;Debug "; " + text$
SetClock(3579545)
If OpenWindow(#Window, 100, 200, 420, 140, "", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
;If ReadFile(0, "G:\DISTR\SEREGASOFT\MIDI\PSGinstrum\patch_0F.raw")
;02 00 FF 0A 09 0A 14
;0 Type 2 Or 3 02 02 - PSG tone, 03 - PSG noise
;1 Noise Data [0,7] 00
;2 Attack Rate [0,$FF] FF
;3 Sustain Level [0,$F] 0A
;4 Attack Level [0,$F] 09
;5 Decay Rate [0,$FF] 0A
;6 Release Rate [0,$FF] 14
;CloseFile(0)
;EndIf
;lets image that was read as:
type = 2
noisedata = 0
attackrate = $10
sustainlevel = $05
attacklevel = $00
decayrate = $05
releaserate = $14
FillARarray(attackrate, attacklevel)
FillDRarray(decayrate, attacklevel, sustainlevel)
FillRRarray(releaserate)
ButtonGadget(#Load, 10, 10, 50, 20, "load")
ButtonGadget(#Gadget, 10, 40, 50, 20, "play")
x = 70
ButtonGadget(#AtRP, x+40, 10, 20, 20, "+")
StringGadget(#AtRG, x+20, 10, 20, 20, Str(attackrate), #PB_String_Numeric | #PB_String_ReadOnly)
ButtonGadget(#AtRM, x, 10, 20, 20, "-")
GadgetToolTip(#AtRG, "Attack Rate")
x + 70
ButtonGadget(#AtLP, x+40, 10, 20, 20, "+")
StringGadget(#AtLG, x+20, 10, 20, 20, Str(attacklevel), #PB_String_Numeric | #PB_String_ReadOnly)
ButtonGadget(#AtLM, x, 10, 20, 20, "-")
GadgetToolTip(#AtLG, "Attack Level")
x + 70
ButtonGadget(#DcRP, x+40, 10, 20, 20, "+")
StringGadget(#DcRG, x+20, 10, 20, 20, Str(decayrate), #PB_String_Numeric | #PB_String_ReadOnly)
ButtonGadget(#DcRM, x, 10, 20, 20, "-")
GadgetToolTip(#DcRG, "Decay Rate")
x + 70
ButtonGadget(#SyLP, x+40, 10, 20, 20, "+")
StringGadget(#SyLG, x+20, 10, 20, 20, Str(sustainlevel), #PB_String_Numeric | #PB_String_ReadOnly)
ButtonGadget(#SyLM, x, 10, 20, 20, "-")
GadgetToolTip(#SyLG, "Systain Level")
x + 70
ButtonGadget(#RrRP, x+40, 10, 20, 20, "+")
StringGadget(#RrRG, x+20, 10, 20, 20, Str(releaserate), #PB_String_Numeric | #PB_String_ReadOnly)
ButtonGadget(#RrRM, x, 10, 20, 20, "-")
GadgetToolTip(#RrRG, "Relise Rate")
CreateImage(#Img01, 280, 70)
CreateImage(#Img02, 280, 70)
ImageGadget(#Gadget2, 100, 40, 280, 70, ImageID(#Img01), #PB_Image_Border)
CreateThread(@PSGPlay(), 123)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
EvGadget = EventGadget()
Select EvGadget
Case #Gadget
;set frequency
;0 ch, tone
writevalue = %10000000 + GetBits(PSGnote($22), 0, 3)
Write(writevalue)
writevalue = GetBits(PSGnote($22), 4, 7)
Write(writevalue)
psgstart = 60 ; duration
psgmarker = psgstart
PhaseOfPSG = 0 ; 0 - Attack Rate, 1 - Decay Rate, 2 - Relise Rate
Case #Load
tmppath$ = OpenFileRequester("enter path to RAW file", "", "RAW Files (*.raw)|*.raw;", 0)
If tmppath$
If FileSize(tmppath$) = 7
If ReadFile(0, tmppath$)
type = ReadAsciiCharacter(0)
noisedata = ReadAsciiCharacter(0)
attackrate = ReadAsciiCharacter(0)
sustainlevel = ReadAsciiCharacter(0)
attacklevel = ReadAsciiCharacter(0)
decayrate = ReadAsciiCharacter(0)
releaserate = ReadAsciiCharacter(0)
CloseFile(0)
If attackrate > 32
attackrate = 32
ElseIf attackrate < 1
attackrate = 1
EndIf
If decayrate > 32
decayrate = 32
ElseIf decayrate < 1
decayrate = 1
EndIf
If releaserate > 32
releaserate = 32
ElseIf releaserate < 1
releaserate = 1
EndIf
FillARarray(attackrate, attacklevel)
FillDRarray(decayrate, attacklevel, sustainlevel)
FillRRarray(releaserate)
SetGadgetText(#AtRG, Str(attackrate))
SetGadgetText(#SyLG, Str(sustainlevel))
SetGadgetText(#AtLG, Str(attacklevel))
SetGadgetText(#DcRG, Str(decayrate))
SetGadgetText(#RrRG, Str(releaserate))
EndIf
Else
MessageRequester("attention!", "probably it is not PSG instrument file.")
EndIf
EndIf
Case #AtRP
attackrate = Val(GetGadgetText(#AtRG))
If attackrate < 32
attackrate + 1
FillARarray(attackrate, attacklevel)
SetGadgetText(#AtRG, Str(attackrate))
EndIf
Case #AtRM
attackrate = Val(GetGadgetText(#AtRG))
If attackrate > 1
attackrate - 1
FillARarray(attackrate, attacklevel)
SetGadgetText(#AtRG, Str(attackrate))
EndIf
Case #AtLP
attacklevel = Val(GetGadgetText(#AtLG))
If attacklevel > 0
attacklevel - 1
FillARarray(attackrate, attacklevel)
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#AtLG, Str(attacklevel))
EndIf
Case #AtLM
attacklevel = Val(GetGadgetText(#AtLG))
If attacklevel < 15
attacklevel + 1
FillARarray(attackrate, attacklevel)
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#AtLG, Str(attacklevel))
EndIf
Case #DcRP
decayrate = Val(GetGadgetText(#DcRG))
If decayrate < 32
decayrate + 1
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#DcRG, Str(decayrate))
EndIf
Case #DcRM
decayrate = Val(GetGadgetText(#DcRG))
If decayrate > 1
decayrate - 1
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#DcRG, Str(decayrate))
EndIf
Case #SyLP
sustainlevel = Val(GetGadgetText(#SyLG))
If sustainlevel > 0
sustainlevel - 1
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#SyLG, Str(sustainlevel))
EndIf
Case #SyLM
sustainlevel = Val(GetGadgetText(#SyLG))
If sustainlevel < 15
sustainlevel + 1
FillDRarray(decayrate, attacklevel, sustainlevel)
SetGadgetText(#SyLG, Str(sustainlevel))
EndIf
Case #RrRP
releaserate = Val(GetGadgetText(#RrRG))
If releaserate < 32
releaserate + 1
FillRRarray(releaserate)
SetGadgetText(#RrRG, Str(releaserate))
EndIf
Case #RrRM
releaserate = Val(GetGadgetText(#RrRG))
If releaserate > 1
releaserate - 1
FillRRarray(releaserate)
SetGadgetText(#RrRG, Str(releaserate))
EndIf
EndSelect
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Quit = 1
EndIf