After reading and researching numerous documents, and scanning other peoples source code for clues, I've produced one of the hardest projects I've ever worked on... a Nintendo Emulator. Yep, you can play the good ol 8 bit NES on your PC. It has both software rendering (StretchDIBits) and Hardware rendering (DirectX). It's practically the only NES emulator written in vb6 that actually has pure sound using DirectSound! I also put in a low pass filter for the sound. You can also seemlessly go from windowed to fullscreen and back with no issues in both software and hardware. And has Load States and Save States. I even included the classic Super Mario Bros so you can test it out right away.
Note: in IDE mode, it'll be way too slow for testing (6-8 fps with sound on, 12-15 fps with sound off). You must compile to exe and use the exe for a full speed of 60 fps. Another thing is that you must have the vb6 version of DirectX to even use the sound or hardware mode. In other words, you must have the dx8vb.dll on your computer over in your system folder and have it registered using regsvr32.exe. This is needed if you have Windows 7 or 8. Windows Vista and below should already have it preinstalled so you don't need the file let alone have to go through a process of registering it.
Note For Windows 7 & 8 users: this will not be shown in your References. And you will only need to do these parts once ever:
- Put the dx8vb.dll file in your Windows\SysWOW64 folder.
- Drag it into regsvr32.exe to register it in order to use it in VB6 from now on and have it shown in References.
- Go ahead and reopen Visual Basic 6 and check the References again to see if it's there.
If it's still not there, the best approach is to run Command Prompt as an Administrator and reference it, as sometimes simply dragging a file into regsvr32 is not enough. To do this:
- Goto your Start Menu.
- click on the bottom where it says > All Programs and goto Accessories
- Right click Command Prompt.
- Click Run as administrator (should be located under Open).
- Next type regsvr32 "YOUR FILE PATH HERE OF DX8VB.DLL" For example:
regsvr32 "C:\Windows\SysWOW64\dx8vb.dll"
I still have a looooong way to go before its complete but here are the version numbers history of known issues and hot fixes:
Version 0.65
Fixed some of the nametable scrolling issues such as Super Mario Bros' scrollboard flickering
Added the ability to view the frames per second in windowed and fullscreen. Although ghetto, itll suffice for now.
Inlined some of the subs to speed things up a notch.
Minor sound calibration tweaks.
Version 0.60
The ENTIRE color palette has been changed into authentic NES color to the actual NES. Although there is no true palette values from the actual NES, and too many sites produced misleading information on the palette, I found the true composite colors from a forum post, added it to my emulator, and compared it to my real NES. It was exactly the same, and the greens weren't too green like the real NES, the sky in Super Mario was exactly alike, etc. How do I know this when brightness, contrasts, and tint could be different from a TV and monitor? My computer is hooked into my TV through an HDMI cable. I can just bounce back and forth between HDMI and Video to compare.
Fixed and added Noise channel. However, although sounds great on many games such as Double Dragon, I'm not hearing bricks breaking in Super Mario Bros.
Added Mapper 2 support so you can play games such as Contra!
Fixed the looping sound issue when you have focus on the menu.
Reading and Writing from the address registers from $0000 to $FFFF has been inlined which produced a huge increase in emulator speed. No more minor slowdowns from time to time like before.
Sound has been tweaked to make it a tad more authentic and consistant with the documentation.
Sound Debugger got many more things added such as noise channel, and square channels now show sweep info.
Code has been cleaned up a notch.
Many other minor fixes I can't name from the top of my head.
Known Issues for v0.60:
Legend of Zelda is saving a save file, and loading but in game, it shows no save game exist. Possibly need to play further to really know for sure.
Square channels work great but doesn't sound authentic enough. Go into a pipe to see what I mean in Super Mario Bros.
Noise channel works great but doesn't sound authentic enough such as no brick breaking noise in Super Mario Bros.
DMC channel has NOT been programmed yet for voice samples. Play Kung Fu and you'll notice something missing to see what I mean.
Version 0.55
Added Mapper 1 support for games such as
-Double Dragon
-Castlevania 2: Simons Quest
-Legend of Zelda
..and much more. Again refer to the NES mapper list on Google to find out more Mapper 1 games.
Fixed the Triangle sound channel. Now it plays and halts perfectly as should.
Added a much more sophisticated sound debugger.
Version 0.50
Only mapper 0 games are supported in the mean time till I perfect everything.
-Super Mario Bros
-1942 (J)
-Kung Fu
-10 Yard Fight
-Robot Block (Stack-Up)
-Robot Gyro (Gyromite)
...etc
Google up NES Mapper List to see a complete list to find other mapper 0 games.
Nametable Scrolling for the background is a little messed up. So you'll see anomalies such as flickering on the score board in Super Mario Bros ever other section of each level.
The NES has 5 channels for sound. Rectangle 1, Rectangle 2, Triangle, Noise, and DMC. I shut off Noise by enabling it false cause it causes slowdown later on. This is a known issue thatll be resolved soon. I also didn't program the DMC yet. So only 3 sound channels are working.
The sound itself is good but sometimes a tiny bit scratchy.
1942 (J) when paused causes the SamplingCount to skyrocket at warp speed even though no sound is playing, causing overflow if left for a short period of time.
I will be constantly updating this program with new revisions as I go along. Enjoy
[EDIT] I will no longer delete each old project to replace it with a new one. Instead I will have up just 5 of the latest just so the number of downloads don't keep getting knocked back to 0, and you can examine the old code for educational purposes. If the project gets complete enough, I may port this to VB.Net as well just so an NES emulator in VB.Net exists if it doesn't already.
Last edited by Jacob Roman; May 14th, 2013 at 03:50 PM.
ok.. i have tested, like and i have something for tell you:
1 - when the user go to the menu: pause the game inclued sound off(or you think that you are ear risk CD). play a game and go to menu and you see what i mean;
2 - let user choose the keys(joypad too, if possible);
3 - i see some(rare, but i see) flickers.
but it's great.. good job
(maybe you can share what you read for doing these)
As for the flickering, thats the Nametable Scrolling issue I was talking about, and its minor. Ill try and fix most of the problems you mentioned but at the moment im still tweeking with the sound so its authentic and perfect. The Noise channel is better but a notch off on some games. i havent uploaded it yet but the slowdown is gone from the noise as well as the horrific sound from that channel. I have more documentation if you need it.
Very large job - well done
Unfortunately it was very slow on my old xp box Pentium D 3.0 Ghz (both with Dx and Non)
I tested only with the the super mario rom and with compiled code. It was about 4 fps and sound was breaking up every second or so.
Sound debugged showed check marks in all boxes and my sound card is Dx compatible.
Thanks for the feedback. I think before I upload the update which I was gonna do this weekend, I should inline a few functions and subs to help give it a speed boost. If you disable the sound you might make it a little faster, since the for loop is mixing the sound and probably causing a one sec delay on your comp. On my comp it goes 60 fps when compiled. But, nothing wrong with a little optimization
Ok after a number of requests I received, apparently its slow on the slower computers, but 60 fps on mine. So I did a little research on some speed optimization starting with VB6 compiler speed tips. For example, I don't need the overflow checks. So doing things like that will dramatically boost the speed of the emulator. I also need to see how I can boost the speed of the program itself with all the things that are doing but it comes at a cost unfortunately...readability. First thing I'm gonna do is a lot of experimenting with another program and test whats faster such as just having a sub/function there or literally Call the sub/function. I also heard \ is faster than both / and * so I'm gonna test it to truely know for sure. Inlining some functions and subs is another way. And it just goes on an on what I need to do. I also got a request to fix the menu exit, so I'm also gonna do that.
Hi, I'm omundodogabriel, creator of YoshiNES. I did YoshiNES alone, using as a basis the code BasicNES. I'm happy to see that there is still someone who cares for emulation in vb6.
Well, I wanted to implement the sound wave using WaveOut in vb6, but I not have much experience working with this sound API.
I have been interested in trying to make your sound code work with WaveOut API, if you authorize. Using Directx with vb6 I did not find very interesting, because it only supports up to DirectX 7 and has no compatibility with older versions of windows.
Take a look at YoshiNES 0.7, where some of the bugs you mentioned have been fixed.
Sure if you want to. Its freely available for modification. And if you really want to, maybe we can work on this project together. Btw VB6 also supports DirectX8 and with some minor tweeks even DirectX9. Operating systems XP and up have DirectX already preinstalled with the operating system. So its ok to work with DirectX in VB6. My emulator uses DirectX8. That file I have above are for those who have Windows 7 and Windows 8 since MS has dropped support for vb6.
Glad to finally chat with the creator of YoshiNES We should totally work on this thing. Best to work as a team and share knowledge
Last edited by Jacob Roman; May 12th, 2013 at 12:39 PM.
Most of the credits go to Don Jarret and David Finch, the authors of bnes, who wrote the code for the CPU. I think it is worth trying to use DirectX 9 in vb.
I agree that we should work together on this project, just can't help with APU emulation. I'll stop the development of YoshiNES to work on this project.
I'm currently working on the support Mapper 5, which is one of the most complex of the NES in my opinion. Only Castlevania 3 is working at the moment, and only menu. : (
I have a code that generates the Nes pallete and looks very similar to the original. I think it might be useful.
Just one problem. They based their cpu off of the 6502c processor, not the 6502. Plus the execution cycle times differed from the 6502. So many thanks to the 2 links up there I found on the 6502 instruction set, so as a result I created a better 6502 module. I also found a couple opcodes needed more code or slightly changed after examining numerous opensource emulators as well as some other documentation on how to execute each instruction.
My APU is currently in its beta stages, and whats really slowing it down is the For Loop on the sound buffer where the sound is mixed. Most languages can handle this such as C# and C++. But making it fast in vb6 is a real challenge. I may have to split up the buffers more so, so the for loop isnt stressing the main loop. Inlining some functions is another way, but it comes at an unfortunate cost, which is readability. Funny thing is, I get a blazing 320 fps average with the sound on my computer when I shut off the Lock_FPS, which locks the framerate to whatever frames per second you desire. And thats with software rendering. So on my computer the sounds fine. However I'm gonna continue to optimize it. Well....it could be because I already optimized the hell out of it but didn't upload it yet.
[EDIT] For now I'm gonna stick with DirectX8 since it coincides with vb6 by default, and not too many people don't know how to get vb6 to work with DX9. I don't wanna risk running into problems and end up reverting back to DirectX8. That would suck!
Also, since you messaged me about mapper 5, here are a couple of files to get you on the go, with C# source code you might be able to convert to vb6, as well as this link to all the mappers with docs to each:
After searching for the problem that was causing flicker when scrolling, I managed to fix using jsnes code.
It was actually very simple, I just replaced this code on write6502 function:
PPUAddress2 = (PPUAddress2 And &HFFE0&) Or (Value And &HF8) \ 8
- with this -
PPUAddress2 = Value \ 8 And &H1F
And flickers are gone. However, when trying to use the code on your emulator, it not worked
I am attaching the YoshiNES code with the bug fixed. I hope you can adapt to your emulator. YoshiNES scroll_fix.zip
You also need to take a look at your 6502 code. vb returned an overflow error in SP on function Push8 after a while playing battletoads.
[EDIT] Guess what. I put it in my updated version of my NES emulator (the one I didn't upload yet) and it works o.O. Also for some reason the sound was a little funky on your YoshiNES v0.8. I think it has a lot to do with register $4015 where theres suppose to be a call to Sound_Channel_Write_Status_Register. I had some comments why I created this too:
Code:
'http://wiki.nesdev.com/w/index.php/APU
' Writing a zero to any of the channel enable bits will silence that channel and "immediately" set its length counter to 0.
'Note: Not having length counter = 0 when channel is disabled immediately afterwards, or placing length counter = 0 somewhere else in another sub produces
' horrific results.
'Examples: In Super Mario Bros.
' - going into a pipe will cause the sound to loop
' - finishing a level and the score being tallied with your alloted time, the sound keeps looping even after it stopped
' - worse of all, the dark levels such as level 2, almost all the sounds are sweeping waaaaay too hard producing ear piercing results!
'So be sure to keep LengthCounter = 0 here in this sub. Its what the NES does immediately when the channels enabled flag is false anyways.
I'll have to examine your code some more but Im just guessing thats why. Either that or you forgot something from my emulator related to sound.
Last edited by Jacob Roman; May 14th, 2013 at 02:51 PM.
I was right. You are missing a write to $4015, so add this:
Case &H4015&: Sound_Channel_Write_Status_Register Value
I'm looking into my Push8, but it seems ok. Did it crash in a particular opcode? And also even though we fixed Super Mario Bros, Castlevania 1 has minor scrolling problems with the score board.
Last edited by Jacob Roman; May 14th, 2013 at 03:06 PM.
"or you forgot something from my emulator related to sound." - most likely because I have not tidied up the code (you may have noticed that is very messy for now).
good that the code worked I still have to fix the timing problems on my emulator
[EDIT] Thanks, will fix the sound right now!
I'll take look on castlevania and see what I can do.
Last edited by omundodogabriel; May 14th, 2013 at 03:19 PM.
C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter
There's just no reason to use garbage like InputBox. - jmcilhinney
The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber
I found out why it had not worked when I tried to fix the scrolling, the function Write_PPU_Register is not used, instead the ppu code is on the WriteMemory8_Inline function.
The sound is better now, and the emulator a little faster. I'm waiting dmc to hear the characters voices
If only I had the time, I would. I'm fascinated with things like that but unfortunately, at the moment I have to invest the time into boring yet marketable stuff. Hopefully in the future, when I have a solid base to make income, I can spend my coding time doing things that don't pay but are nonetheless, immensely enjoyable. God knows, I have so many pet projects that I'd like to finish and so many new things I'd like to learn.
C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter
There's just no reason to use garbage like InputBox. - jmcilhinney
The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber
There are known problems with my emulator, and this is what I know so far that either I or omundodogabriel need to fix:
The noise channels 93 step mode (I believe) isnt playng sound, which is why in Super Mario Bros you don't hear bricks breaking and only hear half the percussion. However in Double Dragon, its perfect, because it remains in 32767 mode the entire time. But if you remove the .Length_Counter > 0 from the if statement in the Noise_Channel_Render_Sample function, run Super Mario Bros, ignor the constant noise for a min, grab a mushroom, and break a block, you will finally hear the brick breaking noise that was missing. So I may have to create a look up table to XOR tap like this C++ NES emulator I have did.
The rectangle channels sounds semi perfect, but going into pipes in Super Mario Bros doesnt sound authentic enough. Those channels might need a minor tweak.
DMC channel is in the works for voice samples.
Games such as Castlevania still has scrolling issues in the scroll board as you move.
Might need to darken one of the turquoise blues in the palette to match up with my actual NES. This color you mainly see in World 1-2 of Super Mario Bros.
I'm working to fix problems in PPU. I fixed some problems based on virtuanes source code and loopy docs, and fixed games like yo noid and arch rivals. Castlevania, however, still flickering
Hmmm that is interesting, but where exactly did you get this information from? If another emulator written in C++ had different ticks than the documentation, it could possibly be wrong. But if it executes better than expected, then there could be a chance the documentation was wrong just like people were wrong on the NTSC palette.
Speaking of palettes, I've been lately tweaking with the values to match more with my NES's colors. Not quite done yet but this is what I have so far where I commented. Believe it or not, this took 2 hours to nail down after tons of tweaks:
vb Code:
Public Sub Create_Real_NES_Pallete_NTSC()
'This is based on the pallete from [url]http://forums.nesdev.com/viewtopic.php?f=21&t=8121[/url]
'In my opinion this is closer to the NES than the other NTSC pallete
Dim Current_Color As Long
'Row 1
Pallete(0) = NES_RGB(104, 104, 104)
Pallete(1) = NES_RGB(0, 42, 136)
Pallete(2) = NES_RGB(20, 18, 167)
Pallete(3) = NES_RGB(59, 0, 164)
Pallete(4) = NES_RGB(92, 0, 126)
Pallete(5) = NES_RGB(110, 0, 64)
Pallete(6) = NES_RGB(108, 6, 0)
Pallete(7) = NES_RGB(86, 29, 0) 'One of the coin block animations in Super Mario Bros
Pallete(8) = NES_RGB(51, 53, 0)
Pallete(9) = NES_RGB(11, 72, 0)
Pallete(10) = NES_RGB(0, 82, 0)
Pallete(11) = NES_RGB(0, 79, 8)
Pallete(12) = NES_RGB(0, 64, 77)
Pallete(13) = NES_RGB(0, 0, 0)
Pallete(14) = NES_RGB(0, 0, 0)
Pallete(15) = NES_RGB(0, 0, 0)
'Row 2
Pallete(16) = NES_RGB(173, 173, 173)
Pallete(17) = NES_RGB(21, 95, 217)
Pallete(18) = NES_RGB(66, 64, 255)
Pallete(19) = NES_RGB(117, 39, 254)
Pallete(20) = NES_RGB(160, 26, 204)
Pallete(21) = NES_RGB(183, 30, 123)
Pallete(22) = NES_RGB(151, 19, 2) 'NES_RGB(181, 49, 32) 'Dark Red: Marios suspenders in Super Mario Bros
Pallete(23) = NES_RGB(113, 68, 0) 'NES_RGB(153, 78, 0) 'Brown: Ground Bricks and regular bricks of outdoor worlds in Super Mario Bros
Pallete(24) = NES_RGB(107, 109, 0)
Pallete(25) = NES_RGB(56, 135, 0)
Pallete(26) = NES_RGB(0, 117, 0) 'NES_RGB(12, 147, 0) 'Dark Green: Hills, turtle shells, pipe, top of flag pole in Super Mario Bros
Pallete(27) = NES_RGB(0, 143, 50)
Pallete(28) = NES_RGB(0, 104, 101) 'NES_RGB(0, 124, 141) 'Dark Turquoise: Ground and ceiling bricks in dark worlds such as 1-2 of Super Mario Bros
Pallete(29) = NES_RGB(0, 0, 0)
Pallete(30) = NES_RGB(0, 0, 0)
Pallete(31) = NES_RGB(0, 0, 0)
'Row 3
Pallete(32) = NES_RGB(255, 254, 255)
Pallete(33) = NES_RGB(100, 176, 255)
Pallete(34) = NES_RGB(156, 174, 255) 'NES_RGB(146, 144, 255) 'Sky Blue: Sky of outdoor worlds in Super Mario Bros
Pallete(35) = NES_RGB(198, 118, 255)
Pallete(36) = NES_RGB(243, 106, 255)
Pallete(37) = NES_RGB(254, 110, 204)
Pallete(38) = NES_RGB(254, 129, 112)
Pallete(39) = NES_RGB(234, 158, 34)
Pallete(40) = NES_RGB(188, 190, 0)
Pallete(41) = NES_RGB(180, 196, 0) 'NES_RGB(136, 216, 0) 'Green: Pipes in Super Mario Bros
And although you should never trust the camera for color values since itll never be the same, the colors I did tweak at least matched. The Sky, the brown bricks, the turquoise bricks, the pipes 2 colors, etc. However I didnt tweak Marios shirt yet. Needs darken a tad to match the NES. But I did match his red suspenders at least so far:
Real NES
Emulated NES
I also wouldnt mind trying to simulate that border on the left and right hand side of the screen, rather than just stretch out whats in between. I will need to research it in the docs.
Last edited by Jacob Roman; May 26th, 2013 at 03:06 AM.
I added mid-frame palette chaging, as seen in the picture above (rstrdemo.nes from virtuanes). Had to rewrite portions of the blitscreen code.
Although I already have fixed several problems related to PPU, there are still problems of timing. I took tick table f fakenes, which also corresponds with the virtuanes.
How are you going to emulate on the sound emulation? DMC already working?
Still working on it, but its not quite ready yet. I'm still trying to fix noise, correcting the color palette to match the NES as exact as possible, and some minor optimizations. At the same time I'm also working on my Nintoaster project, which is a fully functional Nintendo inside a toaster (which works great so far). But I'll try to finish it up and have it for ya in the next update.
Also you may wanna put that new palette in that I tweaked in my previous post. The matching colors make it look pretty sharp.
[EDIT] Ok just for the heck of it, I'm gonna link another source, which has links to multiple sources showing the tick counts for the Opcodes and what you should do is compare it with your chart. I believe to match them you go horizontal, then vertical with the Opcode number. Here are the links":
Ok. Another thing I would like to see in my emulator (as well as yours) that I quite frankly am not seeing in other emulators. if you take a look at post #29, I displayed my real NES image of Super Mario Bros and the emulated version from my emulator at the exact spot. If you notice, the real NES has a border on the left and right side of the screen. This holds true in just about every other NES game I pop into my nintendo. Also if you notice, the scoreboard is a lot closer to the top of the screen than the emulated version of the NES. As I was reading everynes.txt, I think I may have found the answer:
Originally Posted by everynes.txt
PPU Dimensions & Timings
------------------------
NTSC/PAL Timings
Item NTSC PAL
Video Clock 21.47727MHz 26.601712MHz
CPU Clock 1.7897725MHz 1.7734474MHz
Clock Divider CPU=Video/12 CPU=Video/15
Cycles/Scanline 113.66; 1364/12 106.53; 1598/15
Total Scanlines 262 (240+22) 312 (240+72)
Frame Rate 60.098Hz 53.355Hz
Visible Screen Resolution
The logical screen resolution processed by the PPU is 256x240 pixels. However
the visible screen resolution is somewhat smaller, due to improper blanking
periods, and eventually due to exceeding the physical dimensions of (NTSC)
displays.
On PAL hardware, the upper 1 scanline, the left 2 pixels, and the right 2
pixels are invisible (displayed as black border). On NTSC hardware, the upper 8
scanlines, and the lower 8 scanlines are often invisible (224 lines visible),
eventually some NTSC screens are hiding only the upper 3 scanlines (237 lines
visible). To be compatible with all types of displays, output valid 256x240 pixels, but
have the relevant information in the <middle> 240x224 pixels (30x28 tiles)
only.
I believe we coded the emulator to be at a resolution of 256x240 rather than 240x224 for NTSC. So for the beginning of the scanline, well need to have the first 8 pixels of the scanline be the color of the background before drawing the actual tiles, as well as have the last 8 pixels of the scanline be the color of the background. The 8 on top and 8 on the bottom as described in the quote I believe are skipped. So I did a little mini test just to screw around with just the top and bottom:
Code:
If Scanline >= 8 And Scanline <= 231 Then '240x224
Render_Sprites Scanline, False
Render_Background Scanline
Render_Sprites Scanline, True
End If
I ran Super Mario Bros, and I think I just simulated the issue with Castlevania rather than have it draw to match the NES (sucks to be me ). So perhaps thats what we need to do. Get our code to coincide with the 240x224 resolution.
Last edited by Jacob Roman; May 28th, 2013 at 01:49 AM.
in fact, I had done it yesterday I had to lower the resolution, because some games show "garbage" after the scanline 232 (yo noid for example). The only thing I did was change the Top property of the picturebox to -8 and decreases the resolution of the form to 224, hiding the extra scanlines.
One thing that is worrying me is that the tests that I did detect the emulator to PAL, not NTSC. I think it has something to do with the timing, because it detects the system as PAL or NTSC through ticks.
As for your sound emulation, in some games the square channels still need some tweaking.
Yea I know. Go into a pipe in Super Mario Bros and youll see what I mean. I'm still trying to fix the sound with all the channels. Theres gotta be something I'm missing. But I'm pretty close at least.
I've been a little busy with work, since they got me working extra days, otherwise I would have responded sooner. I found out why it was cut off from the top and bottom. Its because I'm using an HDTV. If I were to use an old school tube TV, it would not be cut off. I found out the hardway after seeing footage on YouTube from old tvs. But there is possibility to add an option to set the Nintendo Emulator to HDTV mode o.O. I don't wanna just make the picturebox -8 though. That would be cheating and not work well fullscreen. I prefer to do it programmably. I did the bottom part at least over in Render_Scanline() by making If Scanline >= 232 Then Exit Sub, rather than 240.
I'm not quite finished adjusting the color palette but I made more tweaks, even with the colors I did tweak so it looks even more so like the actual NES. Its a pain trying to match it precisely. But heres what I have so far:
Code:
Public Sub Create_Real_NES_Pallete_NTSC()
'This is based on the pallete from http://forums.nesdev.com/viewtopic.php?f=21&t=8121
'In my opinion this is closer to the NES than the other NTSC pallete
Dim Current_Color As Long
'Row 1
Pallete(0) = NES_RGB(104, 104, 104)
Pallete(1) = NES_RGB(0, 42, 136)
Pallete(2) = NES_RGB(20, 18, 167)
Pallete(3) = NES_RGB(59, 0, 164)
Pallete(4) = NES_RGB(92, 0, 126)
Pallete(5) = NES_RGB(110, 0, 64)
Pallete(6) = NES_RGB(108, 6, 0)
Pallete(7) = NES_RGB(86, 29, 0) 'One of the coin block animations in Super Mario Bros
Pallete(8) = NES_RGB(51, 53, 0)
Pallete(9) = NES_RGB(11, 72, 0)
Pallete(10) = NES_RGB(0, 82, 0)
Pallete(11) = NES_RGB(0, 79, 8)
Pallete(12) = NES_RGB(0, 64, 77)
Pallete(13) = NES_RGB(0, 0, 0)
Pallete(14) = NES_RGB(0, 0, 0)
Pallete(15) = NES_RGB(0, 0, 0)
'Row 2
Pallete(16) = NES_RGB(173, 173, 173)
Pallete(17) = NES_RGB(21, 95, 217)
Pallete(18) = NES_RGB(66, 64, 255)
Pallete(19) = NES_RGB(117, 39, 254)
Pallete(20) = NES_RGB(160, 26, 204)
Pallete(21) = NES_RGB(183, 30, 123)
Pallete(22) = NES_RGB(141, 49, 12) 'NES_RGB(181, 49, 32) 'Dark Red: Marios suspenders in Super Mario Bros, Marios hair, mustache, and boots as fire mario.
Pallete(23) = NES_RGB(113, 63, 0) 'NES_RGB(153, 78, 0) 'Brown: Ground Bricks and regular bricks of outdoor worlds in Super Mario Bros
Pallete(24) = NES_RGB(100, 99, 46) 'NES_RGB(107, 109, 0) 'Greenish Yellow 'Marios Shirt
Pallete(25) = NES_RGB(56, 135, 0)
Pallete(26) = NES_RGB(0, 110, 0) 'NES_RGB(12, 147, 0) 'Dark Green: Hills, turtle shells, pipe, top of flag pole in Super Mario Bros
Pallete(27) = NES_RGB(0, 143, 50)
Pallete(28) = NES_RGB(0, 104, 101) 'NES_RGB(0, 124, 141) 'Dark Turquoise: Ground and ceiling bricks in dark worlds such as 1-2 of Super Mario Bros
Pallete(29) = NES_RGB(0, 0, 0)
Pallete(30) = NES_RGB(0, 0, 0)
Pallete(31) = NES_RGB(0, 0, 0)
'Row 3
Pallete(32) = NES_RGB(255, 254, 255)
Pallete(33) = NES_RGB(100, 176, 255)
Pallete(34) = NES_RGB(146, 154, 255) 'NES_RGB(146, 144, 255) 'Sky Blue: Sky of outdoor worlds in Super Mario Bros
Pallete(35) = NES_RGB(198, 118, 255)
Pallete(36) = NES_RGB(243, 106, 255)
Pallete(37) = NES_RGB(254, 110, 204)
Pallete(38) = NES_RGB(254, 129, 112)
Pallete(39) = NES_RGB(225, 184, 114) 'NES_RGB(234, 158, 34) 'Peach/Light Yello: Marios skin, Bright color coins, bright color ? blocks in Super Mario Bros.
Pallete(40) = NES_RGB(188, 190, 0)
Pallete(41) = NES_RGB(175, 196, 0) 'NES_RGB(136, 216, 0) 'Green: Pipes in Super Mario Bros
Pallete(42) = NES_RGB(92, 228, 48)
Pallete(43) = NES_RGB(69, 224, 130)
Pallete(44) = NES_RGB(72, 205, 222)
Pallete(45) = NES_RGB(79, 79, 79)
Pallete(46) = NES_RGB(0, 0, 0)
Pallete(47) = NES_RGB(0, 0, 0)
'Row 4
Pallete(48) = NES_RGB(255, 254, 255) 'White: Super Mario Bros Text
Pallete(49) = NES_RGB(192, 223, 255)
Pallete(50) = NES_RGB(211, 210, 255)
Pallete(51) = NES_RGB(232, 200, 255)
Pallete(52) = NES_RGB(251, 194, 255)
Pallete(53) = NES_RGB(254, 196, 234)
Pallete(54) = NES_RGB(254, 204, 197) 'Pinkish White: Super Mario Logo, White in bricks
Pallete(55) = NES_RGB(247, 236, 225) 'NES_RGB(247, 216, 165) 'Pinkish White 2: Marios Shirt with Fireflower in Super Mario Bros
Pallete(56) = NES_RGB(228, 229, 148)
Pallete(57) = NES_RGB(207, 239, 150)
Pallete(58) = NES_RGB(189, 244, 171)
Pallete(59) = NES_RGB(179, 243, 204)
Pallete(60) = NES_RGB(181, 235, 242)
Pallete(61) = NES_RGB(184, 184, 184)
Pallete(62) = NES_RGB(0, 0, 0)
Pallete(63) = NES_RGB(0, 0, 0)
For Current_Color = 0 To 63
Pallete(Current_Color + 64) = Pallete(Current_Color)
Pallete(Current_Color + 128) = Pallete(Current_Color)
Pallete(Current_Color + 192) = Pallete(Current_Color)
Next Current_Color
End Sub
These days I ported the YoshiNES to vb.net. The main problems I had, is that the rendering is very slow zoom, the speed drops by almost half when I put 2x zoom. This is the code I am using to render:
Code:
Public Sub Blit(ByVal Buffer() As Integer, ByVal W As Integer, ByVal H As Integer, Optional ByVal MyZoom As Integer = 1, Optional ByVal Interpolation As Integer = 5)
Dim bm1 As New Bitmap(W, H, Imaging.PixelFormat.Format32bppRgb)
Dim bm2 As New Bitmap(W * MyZoom, H * MyZoom, Imaging.PixelFormat.Format32bppRgb)
Dim GR As Graphics = Graphics.FromImage(bm2)
GR.InterpolationMode = Interpolation
Dim BitmapData1 As Imaging.BitmapData
BitmapData1 = bm1.LockBits(New Rectangle(0, 0, W, H), Imaging.ImageLockMode.WriteOnly, Imaging.PixelFormat.Format32bppRgb)
Dim Scan0 As IntPtr = BitmapData1.Scan0
Runtime.InteropServices.Marshal.Copy(Buffer, 0, Scan0, W * H)
bm1.UnlockBits(BitmapData1)
GR.DrawImage(bm1, 0, 0, bm2.Width, bm2.Height)
Form1.NesScreen.Image = bm2
End Sub
Another problem was that I could not in any way make the DirectX work in vb.net (my version is Visual Basic Express 2010). I installed the DirectX SDK, and even then DirectX not appear in the Add Reference dialog . My top priority is to make your sound emulation engine work on vb.net
The code is very similar to the original, and any improvements I make in my emu can be easily implemented in yours. I sent you an email with the code if you want to take a look.
A popular graphics framework in use for .Net is called XNA which is a wrapper around DirectX if I'm not mistaken. There are a few XNA guys around here like dday9 and Shaggy Hiker. Maybe you should look up their stuff or ask them about using XNA in VB.Net.
C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter
There's just no reason to use garbage like InputBox. - jmcilhinney
The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber
Nah I'm gonna stick with DirectX. Theres no point of using another graphics library.
And this is how you put DirectX9 in VB.Net:
Code:
-------------------------------
VB.Net 2010
-------------------------------
Setting up Project:
- Start a new project and create a Windows Forms Application.
Setting up for DirectX9:
- Go up in the menu to Project > Add Reference...
- Next goto .NET tab.
- Scroll down to Microsoft.DirectX and click it.
- Hold control and also add Microsoft.DirectX.Direct3D. You are welcome to adding more DirectX references if you choose.
- Click Ok.
Note: If any of the DirectX stuff isn't located in your .NET tab, you may need to manually add it using your Browse tab under (your harddrive letter):\Windows\Microsoft.NET\DirectX For Managed Code\1.0.2902.0 and add your necessary .dll files such as Microsoft.DirectX.dll and Microsoft.DirectX.Direct3D.dll, etc. For any other new projects afterwards, if it's still not there, look under the Recent Tab.
Project must be in X86 for DirectX9 apps to run. And thankfully it's x86 by default. However the .Net Framework is 4.0 and needs changed to 3.5. Here's how to set it up:
- Go towards the right of the screen where it says Solution Explorer.
- Right click your project name and goto Properties.
- On the left side, select Compile.
- Click on the button Advanced Compile Options... A new window should pop up.
- On the bottom where it says Target Framework, select .NET Framework 3.5
- Click Ok.
- You are now ready to code with DirectX
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
I'll take a look at your code, but if I were you, I would stick with the C++ written API's we were using in vb6 rather than the slow built in VB.Net functions from the .NET library.
I checked out your vb.net code and noticed you didn't use Option Strict On. The program executes slower when you dont convert things programmably. If the program itself tries to, its gotta add extra assembly code to do so. Also your timer is not good. Its better to use a Do Loop locked at 60 frames per second such as here:
vb.net Code:
Option Explicit On
Option Strict On
Public Class Form1
Private Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Integer
Private Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Integer
Private Ticks_Per_Second As Long
Private Start_Time As Long
Private Milliseconds As Integer
Private Get_Frames_Per_Second As Integer
Private Frame_Count As Integer
Private Running As Boolean
Private Function Hi_Res_Timer_Initialize() As Boolean
If QueryPerformanceFrequency(Ticks_Per_Second) = 0 Then
I managed to add DirectX to vb.net, and ported all sound emulation code to use with the new DirectSound. However, in runtime, vb show the error NullReferenceException. What I am doing wrong?
Edit: Already discovered the problem, I forgot to call the function DirectSound_Initialize
Now is giving a ArgumentException error on Sound_Process_Through_Mixer function ....
Edit 2: FIXED! It's working perfectly now! NES vb.net emulator now with sound! The source with working sound engine is attached! OMG, i can ever hear bricks breaking now!
Code:
Option Explicit On
Imports Microsoft.DirectX
Imports Microsoft.DirectX.DirectSound
Module DSound
'Public DX As DirectX9
'Public DirectSound_Enum As Enum
Private Sound_Device As New Device
Public Sound_Buffer As SecondaryBuffer
Private Sound_Buffer_Description As New DirectSound.BufferDescription()
Public Sound_Buffer_Wave_Format As New WaveFormat()
Public Const MAX_VOLUME As Long = 100
Public Buffer_Length As Long, Half_Buffer_Length As Long
Public Buffer_Size As Long
Public Sound_Data() As Byte
Public Sub DirectSound_Initialize()
'DX = New DirectSound
'DirectSound_Enum = DX.GetDSEnum
'DirectSound = DX.DirectSoundCreate(DirectSound_Enum.GetGuid(1))
With Sound_Buffer_Wave_Format
.FormatTag = WaveFormatTag.Pcm
.Channels = 1 '1 = Mono 2 = Stereo. The NES is Mono
.BitsPerSample = 16
.SamplesPerSecond = 44100 '22050
.BlockAlign = (.BitsPerSample * .Channels) / 8
.AverageBytesPerSecond = ((.BitsPerSample / 8) * .Channels) * .SamplesPerSecond
Buffer_Size = .AverageBytesPerSecond '* 5
ReDim Sound_Data(Buffer_Size)
Half_Buffer_Length = .AverageBytesPerSecond / 2 '/ 15
Half_Buffer_Length = Half_Buffer_Length + (Half_Buffer_Length Mod .BlockAlign)
End With
Buffer_Length = Half_Buffer_Length * 2
Sound_Device.SetCooperativeLevel(Form1.Handle, CooperativeLevel.Normal)
With Sound_Buffer_Description
.Format = Sound_Buffer_Wave_Format
.BufferBytes = Buffer_Length
'DSBCAPS_STICKYFOCUS - means it will keep playing even if our application does not have focus
.Flags = BufferDescriptionFlags.ControlPositionNotify Or _
BufferDescriptionFlags.StickyFocus Or _
BufferDescriptionFlags.ControlFrequency Or _
BufferDescriptionFlags.ControlPan Or _
BufferDescriptionFlags.ControlVolume
End With
Sound_Buffer = New SecondaryBuffer(Sound_Buffer_Description, Sound_Device)
'DirectSound.CreateSoundBuffer(Sound_Buffer_Description)
Sound_Channel_Clear_Buffer()
Set_Sound_Volume(Sound_Buffer, 100)
Play_Sound_Loop(Sound_Buffer)
'Sound_Buffer.Play(0, DirectSound.BufferPlayFlags.Looping)
End Sub
Public Sub Play_Sound(ByVal Sound_Buffer As SecondaryBuffer)
Sound_Buffer.SetCurrentPosition(0)
Sound_Buffer.Play(0, BufferPlayFlags.Default)
End Sub
Public Sub Play_Sound_Once(ByVal Sound_Buffer As SecondaryBuffer)
Sound_Buffer.Play(0, BufferPlayFlags.Default)
End Sub
Public Sub Play_Sound_Loop(ByVal Sound_Buffer As SecondaryBuffer)
Sound_Buffer.Play(0, BufferPlayFlags.Looping)
End Sub
Public Sub Pause_Sound(ByVal Sound_Buffer As SecondaryBuffer)
Sound_Buffer.Stop()
End Sub
Public Sub Set_Sound_Volume(ByVal Buffer As SecondaryBuffer, ByVal Volume As Long)
If Volume >= MAX_VOLUME Then Volume = MAX_VOLUME
If Volume <= 0 Then Volume = 0
Buffer.Volume = ((Volume / MAX_VOLUME) * 10000) + -10000
End Sub
I have a question Jacob....Why do you use QueryPerformanceCounter ? What's its function ? MSDN says returns a count of a high resolution counter. What does that mean in layman's terms ?
C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter
There's just no reason to use garbage like InputBox. - jmcilhinney
The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber