Help converting from Visual Basic

Just starting out? Need help? Post your questions and find answers here.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

Hi,

I just checked your code and it seems Ok.

One thing:
The formula for a keyboard is

Code: Select all

freq.f = 440 * Pow(2, (KeyNo - 49) / 12)
Key 1 is 27.5Hz (A0)
Key 88 is 4186.01Hz (C8)

That's valid for an 88 key piano.

Bernd
SeregaZ
Enthusiast
Enthusiast
Posts: 617
Joined: Fri Feb 20, 2009 9:24 am
Location: Almaty (Kazakhstan. not Borat, but Triple G)
Contact:

Re: Help converting from Visual Basic

Post by SeregaZ »

for my case i get note value from midi as $xx, then from this procedure get 2 value for 2 registers of cpu and send to this cpu.

and in this days i make rom for emulator sega mega drive and start it and make dump of sound cpu command and see it difference :(((( but now some man says it is shift of octaves. and sure :) $10 + 12 = $1C and this $1C shows correct values $A4 = B and $A0 = 2B

false alarm :) i am as always - dubmass...
SeregaZ
Enthusiast
Enthusiast
Posts: 617
Joined: Fri Feb 20, 2009 9:24 am
Location: Almaty (Kazakhstan. not Borat, but Triple G)
Contact:

Re: Help converting from Visual Basic

Post by SeregaZ »

it is a little offtop of converting, but still about this function:
now i want to make back convert operation of two registers values to another one: note and pitch value. my idea is first make some array of notes and values of notes, fill it, and then compare with input data:

Code: Select all

Global Dim tiks.i(12)
tiks(1)  = 7
tiks(2)  = 7
tiks(3)  = 6
tiks(4)  = 6
tiks(5)  = 6
tiks(6)  = 5
tiks(7)  = 5
tiks(8)  = 5
tiks(9)  = 5
tiks(10) = 4
tiks(11) = 4
tiks(12) = 4

Structure RegistersVal
  
  note.i  ; C
  A4A0.i  ;
  ptik.f  ;
  
EndStructure

Global Dim RegistersDataBase.RegistersVal(0)

Structure notptc
  note.i
  pitch.i
EndStructure

Procedure.i GetOPNNote(Note.i, Pitch.i)
  
  Protected.d FreqHz, CurNote
  Protected.i BlkNum, FNum
  
  CurNote = Note + Pitch / 128
  
  FreqHz = 440 * Pow(2, (CurNote - 69) / 12)
  
  BlkNum = Note / 12 - 1

  If BlkNum < 0
    BlkNum = 0
  ElseIf BlkNum > 7
    BlkNum = 7
  EndIf  
 
  FNum = Round((144 * FreqHz / 7670454) * Pow(2, 21 - BlkNum), #PB_Round_Nearest)
  If FNum < 0
    FNum = 0
  ElseIf FNum > $7FF
    FNum = $7FF
  EndIf 

  ProcedureReturn FNum | (BlkNum * $800)

EndProcedure

Procedure.i RetNotAndPithc(A4A0.i)
  
  For i = ArraySize(RegistersDataBase()) To 1 Step -1
    If RegistersDataBase(i)\A4A0 < A4A0
      ;Debug "$" + RSet(Hex(RegistersDataBase(i)\note), 2, "0")
      ;Debug "$" + RSet(Hex((A4A0 - RegistersDataBase(i)\A4A0) * RegistersDataBase(i)\ptik), 4, "0")
      
      tmp$ = RSet(Bin((A4A0 - RegistersDataBase(i)\A4A0) * RegistersDataBase(i)\ptik), 16, "0")
      tmp$ = Bin(RegistersDataBase(i)\note) + tmp$
      tmp = Val("%" + tmp$)
      
      Break
    EndIf
  Next
  
  ProcedureReturn tmp
  
EndProcedure

;FNum = GetOPNNote($0C, 0)
;Debug "$A4 " + RSet(Hex(FNum >> 8), 2, "0")
;Debug "$A0 " + RSet(Hex(FNum & $FF), 2, "0")


  tik = 1
  For n = $0C To $5F
  
    FNum = GetOPNNote(n, 0) 
    ReDim RegistersDataBase(ArraySize(RegistersDataBase())+1)
    RegistersDataBase(ArraySize(RegistersDataBase()))\note = n
    RegistersDataBase(ArraySize(RegistersDataBase()))\A4A0 = FNum
    RegistersDataBase(ArraySize(RegistersDataBase()))\ptik = tiks(tik)
    tik = tik + 1
    If tik = 13
      tik = 1
    EndIf  
  Next

  NAP = RetNotAndPithc($2B9F)
  
how to return two values from procedure more elegant? without allocate memory - it will be used in thread, i think this allocate will make some little mess in future.
tmp$ = RSet(Bin((A4A0 - RegistersDataBase(i)\A4A0) * RegistersDataBase(i)\ptik), 16, "0")
tmp$ = Bin(RegistersDataBase(i)\note) + tmp$
tmp = Val("%" + tmp$)
this part of code is terrible. i am just not full understans this >>, << and &... and many other operation. this my NAP must be split into 2 value.
Wolfram
Enthusiast
Enthusiast
Posts: 567
Joined: Thu May 30, 2013 4:39 pm

Re: Help converting from Visual Basic

Post by Wolfram »

SeregaZ wrote:for my case i get note value from midi as $xx, then from this procedure get 2 value for 2 registers of cpu and send to this cpu.

and in this days i make rom for emulator sega mega drive and start it and make dump of sound cpu command and see it difference :(((( but now some man says it is shift of octaves. and sure :) $10 + 12 = $1C and this $1C shows correct values $A4 = B and $A0 = 2B

false alarm :) i am as always - dubmass...
I'm not sure that I understand your problem right. But if you work with MIDI you should know that some companies use note no. 60 as C3 and some as C4.
But C3 is the right note.
macOS Catalina 10.15.7
SeregaZ
Enthusiast
Enthusiast
Posts: 617
Joined: Fri Feb 20, 2009 9:24 am
Location: Almaty (Kazakhstan. not Borat, but Triple G)
Contact:

Re: Help converting from Visual Basic

Post by SeregaZ »

with midi to game no problem :) almost ready and work fine (just instruments left). now time of vgm to game part :)
SeregaZ
Enthusiast
Enthusiast
Posts: 617
Joined: Fri Feb 20, 2009 9:24 am
Location: Almaty (Kazakhstan. not Borat, but Triple G)
Contact:

Re: Help converting from Visual Basic

Post by SeregaZ »

i am not sure... but i make some experiments with >>, << and & commands... and i think:

Code: Select all

tmp$ = RSet(Bin((A4A0 - RegistersDataBase(i)\A4A0) * RegistersDataBase(i)\ptik), 16, "0")
tmp$ = Bin(RegistersDataBase(i)\note) + tmp$
tmp = Val("%" + tmp$)
to change:

Code: Select all

tmp = RegistersDataBase(i)\note << 16 + ((A4A0 - RegistersDataBase(i)\A4A0) * RegistersDataBase(i)\ptik)
and then read it some kind of this:

Code: Select all

Debug tmp >> 16
Debug tmp & $FF
__________________________________________________
Code tags added
04.01.2016
RSBasic

__________________________________________________
Thanks
SeregaZ
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Help converting from Visual Basic

Post by Lunasole »

Not sure it is needed anymore, but I write something about your previous code 8)

Code: Select all

128#  - # marks "double" number in VB6, kind of variable extensions like String$ in PB. Should be translated as 128.0
^     - equivalent of Pow ()
\     - in VB6 it was "integer division", division with always rounding result down, unlike / which returns floating result and rounding it to nearest integer. PB equivalent for \ is /
And   - in VB6 logical AND, both used in comparing and calculating. PB has more stupid mess with it, it uses AND with IF statements and "&" to calculate something

What about <<, I didn't tested your code, but if just need to to assemble variable from several lesser ones, maybe you can use something like

Code: Select all

Structure DWORD 
	LOWORD.u ; represents the first 2 bytes of LONG
	HIWORD.u ; the second part of LONG
EndStructure

Structure ALLTHESTUFF 
	StructureUnion
		LONG.l
		_LONG.DWORD
	EndStructureUnion
EndStructure
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
marcos.exe
User
User
Posts: 20
Joined: Fri Jan 17, 2020 8:20 pm

Re: Help converting from Visual Basic

Post by marcos.exe »

SeregaZ wrote: Tue Aug 18, 2015 8:52 am FNum >> 8 i read something about it... it some kind of shift, right?
FNum & $FF what this & means? some kind of +, but more as + for string, not mathematiks?
Hey!
Does this code still work in 2023?

Error:
[ERROR] Invalid memory access. (write error at address 0)
Content:
OPNhdll = OpenLibrary(0, "OPN_DLL.dll")
I tried:
OPNhdll = OpenLibrary(#PB_Any, "OPN_DLL.dll")
But "OPNhdll " remains 0.

Note: I already had the "OPN_DLL.dll" library on my pc, which came from the original visual basic project mentioned above.

Did the code work well for you?
When our generation/OS updates, we either update ourselves, or we are removed.
But we are never fully uninstalled.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

The dll needs to be by side of the executable.
If you use the 64bit PB you need a 64bit dll.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

According to the source code of opn_dll
https://forums.sonicretro.org/index.php ... 337/page-4
it should look like this:

Code: Select all

OPNhdll = OpenLibrary(#PB_Any, "OPN_DLL.dll")
If OPNhdll
  Prototype.a Prototype_OpenOPNDriver(Chips.a)
  Prototype Prototype_CloseOPNDriver()
  Prototype Prototype_OPNWrite(ChipID.a, Register.u, Dat.a)
  
  
  Global OpenOPNDriver.Prototype_OpenOPNDriver = GetFunction(OPNhdll, "OpenOPNDriver")
  Global CloseOPNDriver.Prototype_CloseOPNDriver = GetFunction(OPNhdll, "CloseOPNDriver")
  Global OPN_Write.Prototype_OPNWrite = GetFunction(OPNhdll, "OPN_Write")  
EndIf
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

An extended version: (compiles and works with PB Windows x86)

Code: Select all

EnableExplicit

; https://newt.phys.unsw.edu.au/jw/notes.html
Enumeration 60  ; middle C key on a MIDI kbd (C4)
  #Note_Do
  #Note_Do_
  #Note_Re
  #Note_Re_
  #Note_Mi
  #Note_Fa
  #Note_Fa_
  #Note_Sol
  #Note_Sol_
  #Note_La
  #Note_La_
  #Note_Si
EndEnumeration

#YM2612_CLOCK	= 7670454


Procedure.i GetOPNNote(MidiKey.i, Pitch.i)
  
  Protected.d FreqHz, CurNote
  Protected.i BlkNum, FNum
  
  
  CurNote = MidiKey + Pitch / 128
  FreqHz = 440 * Pow(2, (MidiKey - 69) / 12)
  
  BlkNum = MidiKey / 12 - 1
  If BlkNum < 0
    BlkNum = 0
  ElseIf BlkNum > 7
    BlkNum = 7
  EndIf
  
  FNum = Round((144 * FreqHz / #YM2612_CLOCK) * Pow(2, 21 - BlkNum), #PB_Round_Nearest)
  If FNum < 0
    FNum = 0
  ElseIf FNum > $7FF
    FNum = $7FF
  EndIf 
  
  ProcedureReturn FNum | (BlkNum * $800)
  
EndProcedure

; Resampling Modes
#OPT_RSMPL_HIGH	= $00     ; high quality linear resampling [Default]
#OPT_RSMPL_LQ_DOWN = $01  ; low quality downsampling, high quality upsampling
#OPT_RSMPL_LOW = $02      ; low quality resampling

; Chip Sample Rate Modes
#OPT_CSMPL_NATIVE = $00   ; native chip sample rate [Default]
#OPT_CSMPL_HIGHEST = $01  ; highest sample rate (native Or custom)
#OPT_CSMPL_CUSTOM = $02   ; custom sample rate



Define.i OPNhdll, Event, Quit, KeyNo, FNum


OPNhdll = OpenLibrary(#PB_Any, "OPN_DLL.dll")

If OPNhdll
  Prototype Prototype_SetOPNOptions(OutSmplRate.l, ResmplMode.a, ChipSmplMode.a, ChipSmplRate.l)
  Prototype.a Prototype_OpenOPNDriver(Chips.a)
  Prototype Prototype_CloseOPNDriver()
  
  Prototype Prototype_OPN_Write(ChipID.a, Register.u, Dat.a)
  Prototype Prototype_OPN_Mute(ChipID.a, MuteMask.a)
  
  Prototype Prototype_PlayDACSample(ChipID.a, DataSize.l, *Data.Ascii, SmplFreq.l)
  Prototype Prototype_SetDACFrequency(ChipID.a, SmplFreq.l)
  Prototype Prototype_SetDACVolume(ChipID.a, Volume.u) ;	$100 = 100%

  
  Global SetOPNOptions.Prototype_SetOPNOptions = GetFunction(OPNhdll, "SetOPNOptions")
  Global OpenOPNDriver.Prototype_OpenOPNDriver = GetFunction(OPNhdll, "OpenOPNDriver")
  Global CloseOPNDriver.Prototype_CloseOPNDriver = GetFunction(OPNhdll, "CloseOPNDriver")
  
  Global OPN_Write.Prototype_OPN_Write = GetFunction(OPNhdll, "OPN_Write")
  Global OPN_Mute.Prototype_OPN_Mute = GetFunction(OPNhdll, "OPN_Mute")
  
  Global PlayDACSample.Prototype_PlayDACSample = GetFunction(OPNhdll, "PlayDACSample")
  Global SetDACFrequency.Prototype_SetDACFrequency = GetFunction(OPNhdll, "SetDACFrequency")
  Global SetDACVolume.Prototype_SetDACVolume = GetFunction(OPNhdll, "SetDACVolume")
  
  
  ;- Setup
  If OpenOPNDriver(1) = 0
    
    ; https://plutiedev.com/ym2612-registers
    
    OPN_Write(0, $30, $74)  ; multiplier and detune
    OPN_Write(0, $34, $72)  ; multiplier and detune
    OPN_Write(0, $38, $74)  ; multiplier And detune
    OPN_Write(0, $3C, $71)  ; multiplier And detune
    
    OPN_Write(0, $40, $23)  ; total level
    OPN_Write(0, $44, $26)  ; total level
    OPN_Write(0, $48, $2A)  ; total level
    OPN_Write(0, $4C, $00)  ; total level
    
    OPN_Write(0, $50, $1F)  ; attack rate an rate scaling
    OPN_Write(0, $54, $1F)  ; attack rate an rate scaling
    OPN_Write(0, $58, $19)  ; attack rate an rate scaling
    OPN_Write(0, $5C, $12)  ; attack rate an rate scaling
    
    OPN_Write(0, $60, $00)  ; decay rate and am enable
    OPN_Write(0, $64, $00)  ; decay rate and am enable
    OPN_Write(0, $68, $0E)  ; decay rate and am enable
    OPN_Write(0, $6C, $07)  ; decay rate and am enable
    
    OPN_Write(0, $70, $00)  ; sustain rate
    OPN_Write(0, $74, $00)  ; sustain rate
    OPN_Write(0, $78, $00)  ; sustain rate
    OPN_Write(0, $7C, $00)  ; sustain rate
    
    OPN_Write(0, $80, $07)  ; release rate and sustain level
    OPN_Write(0, $84, $08)  ; release rate and sustain level
    OPN_Write(0, $88, $24)  ; release rate and sustain level
    OPN_Write(0, $8C, $18)  ; release rate and sustain level
    
    OPN_Write(0, $90, $00)  ; SSG-EG (better set to 0)
    OPN_Write(0, $94, $00)  ; SSG-EG (better set to 0)
    OPN_Write(0, $98, $00)  ; SSG-EG (better set to 0)
    OPN_Write(0, $9C, $00)  ; SSG-EG (better set to 0)
    
    OPN_Write(0, $B0, $3B)  ; algorithm and feedback
    
    OPN_Write(0, $B4, $04)  ; panning, PMS, AMS
    OPN_Write(0, $B4, $C0)  ; panning, PMS, AMS
    
    
    If OpenWindow(0, 100, 100, 430, 160, "Piano", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
      
      CanvasGadget(#Note_Do, 20, 30, 30, 90)
      CanvasGadget(#Note_Do_, 55, 30, 20, 60)
      CanvasGadget(#Note_Re, 80, 30, 30, 90)
      CanvasGadget(#Note_Re_, 115, 30, 20, 60)
      CanvasGadget(#Note_Mi, 140, 30, 30, 90)
      CanvasGadget(#Note_Fa, 200, 30, 30, 90)
      CanvasGadget(#Note_Fa_, 235, 30, 20, 60)
      CanvasGadget(#Note_Sol, 260, 30, 30, 90)
      CanvasGadget(#Note_Sol_, 295, 30, 20, 60)
      CanvasGadget(#Note_La, 320, 30, 30, 90)
      CanvasGadget(#Note_La_, 355, 30, 20, 60)
      CanvasGadget(#Note_Si, 380, 30, 30, 90)
      
      If StartDrawing(CanvasOutput(#Note_Do_))
        Box(0, 0, 20, 60, 0)
        StopDrawing()
      EndIf
      
      If StartDrawing(CanvasOutput(#Note_Re_))
        Box(0, 0, 20, 60, 0)
        StopDrawing()
      EndIf
      
      If StartDrawing(CanvasOutput(#Note_Fa_))
        Box(0, 0, 20, 60, 0)
        StopDrawing()
      EndIf
      
      If StartDrawing(CanvasOutput(#Note_Sol_))
        Box(0, 0, 20, 60, 0)
        StopDrawing()
      EndIf
      
      If StartDrawing(CanvasOutput(#Note_La_))
        Box(0, 0, 20, 60, 0)
        StopDrawing()
      EndIf
      
      Repeat
        
        Event = WaitWindowEvent()
        Select Event
          Case #PB_Event_Gadget
            Select EventType()
              Case #PB_EventType_LeftButtonDown
                KeyNo = EventGadget()
                Debug KeyNo
                FNum = GetOPNNote(KeyNo, 0)
                OPN_Write(0, $A4, FNum >> 8)  ; frequency first channel high
                OPN_Write(0, $A0, FNum & $FF) ; frequency first channel low
                
                OPN_Write(0, $28, $F0)        ; Note On - Resume Stream
                
              Case #PB_EventType_LeftButtonUp
                OPN_Write(0, $28, $00)
                
            EndSelect
            
          Case #PB_Event_CloseWindow
            Quit = 1
            
        EndSelect
        
      Until Quit = 1
      
      CloseOPNDriver()
      CloseLibrary(OPNhdll)
      
    EndIf
  EndIf
EndIf
Last edited by infratec on Sat Mar 18, 2023 11:59 pm, edited 2 times in total.
User avatar
Kiffi
Addict
Addict
Posts: 1353
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Re: Help converting from Visual Basic

Post by Kiffi »

infratec wrote: Fri Mar 17, 2023 11:00 pm

Code: Select all

#Note_Do = 66
#Note_Do_ = #Note_Do + 1
#Note_Re = #Note_Do_ + 1
#Note_Re_ = #Note_Re + 1
#Note_Mi = #Note_Re_ + 1
#Note_Fa = #Note_Mi + 1
#Note_Fa_ = #Note_Fa + 1
#Note_Sol = #Note_Fa_ + 1
#Note_Sol_ = #Note_Sol + 1
#Note_La = #Note_Sol_ + 1
#Note_La_ = #Note_La + 1
#Note_Si = #Note_La_ + 1
Small suggestion for improvement:

Code: Select all

Enumeration 66
  #Note_Do
  #Note_Do_
  #Note_Re
  #Note_Re_
  #Note_Mi
  #Note_Fa
  #Note_Fa_
  #Note_Sol
  #Note_Sol_
  #Note_La
  #Note_La_
  #Note_Si
EndEnumeration
Hygge
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

It was not planned this way, :mrgreen:
I had not the half tones in the original code
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help converting from Visual Basic

Post by infratec »

I corrected the version above and added a link for explanations.

Now it represents middle octave C4 - B4 (261.63Hz to 493.88Hz)

But in general: it makes more sense to use midi directly instead of this old dll.
marcos.exe
User
User
Posts: 20
Joined: Fri Jan 17, 2020 8:20 pm

Re: Help converting from Visual Basic

Post by marcos.exe »

infratec wrote: Sat Mar 18, 2023 12:28 pm I corrected the version above and added a link for explanations.

Now it represents middle octave C4 - B4 (261.63Hz to 493.88Hz)

But in general: it makes more sense to use midi directly instead of this old dll.

It was simpler than I thought. I'm running in Pure Basic in the 32bit version, instead of the 64bit version..
It's working fine.
Thank you very much.

But, I'm looking through the documentation to see how to play different channels, and I can't find such an easy to understand explanation.
I even looked for help in the gpt chat, but that doesn't know how to program in PureBasic correctly.
Could you help me with this situation more?

Remembering that I don't want to write anything too complex. I just want to write a program that plays notes in real time.
Because I'm totally blind, I can't use VST's, deflemask, among other programs on the market very well. So I'm having to write my own. And what I've achieved so far is helping me a lot.
I've already created a program for MIDI, and despite some bugs, it works fine for me. Then I will improve it.
But what I need now is to write this one.
Thank you so much again in advance, for everything so far!
When our generation/OS updates, we either update ourselves, or we are removed.
But we are never fully uninstalled.
Post Reply