We're using cookies to ensure you get the best experience on our website. More info
Understood
@guyperfectRegistered December 4, 2012Active 5 months, 3 weeks ago
375 Replies made

3DBoyColor wrote:
I’m curious about something concerning the VB system, is the overall processing power divided between the two screens?

Graphics are usually handled by a dedicated video component in the hardware called VIP (Virtual Image Processor). The CPU overhead for configuring the VIP is usually negligible. You could run into trouble trying to do realtime affine calculations, but most people don’t. (-:

3DBoyColor wrote:
Is the VB twice as powerful if it only has to draw to one of the screens?

As before, the CPU won’t be weighed down one way or the other, so that’s not an issue. Though disabling video could conceivably utilize the VIP as a makeshift coprocessor if you were clever about it… I think you just nerd sniped me.

Having said that, the VIP does draw frames discretely with a top-down procedure, though reverse engineering exactly what that procedure involves is a month-long project in an of itself. What I can say about it is that in profiling experiments, I did not see an increase in drawing capacity when disabling drawing to one display. Apparently it does all the pixel calculations, but at the last moment decides whether or not to apply them.

Check the bottom. I imagine the FCC and CE information written in English only appears in the US release.

Picked up a fourth one for an article/guide on fixing the displays. It’s a US unit.

VN10091489[4]

Dreammary wrote:
Online play will be the ultimate goal for Virtual Boy. 🙂

Hrm. VB connector on one end, USB on the other…

I’ll look into it. If we can reliably make VB-style connectors, this should absolutely be feasible.

Welcome to “Guy Perfect Talks to Himself 2016”!

I’ve completed my Java VSU emulator and ported over the VB sounds engine I wrote for this project. I set up a cobbled mess of tones and interrupting sounds then ran it through both my emulator and the hardware… and Mednafen.

The results are attached to this post, as is a ROM that produces this audio sequence. While we’re never going to get a 100% match with the hardware sample-for-sample, at least we can get awfully darn close.

I took a look at the sound board and saw that it was using 220μF capacitors and 100Ω resistors to cancel the DC bias of the analog output. If you work that into the formula, you get a cutoff frequency of about 7.23hz. My earlier estimation of 10.0hz was based on analysis of recorded sound output, but I’m pleased to say that I know the exact value now.

I’m testing a VSU emulator that I wrote for the music project, and implemented the new RC value based on the components I saw wired into the actual device. There’s still some noise in the hardware line and the usual analog oddities, but holy smokes, my output matches almost exactly both for amplitude as well as timing.

Attachments:

Neat, I stumbled on a most interesting find…

I missed an unanswered question before. The question was: “Is the sweep shift amount taken as-is or is 1 added to it like most of the other register fields?” The answer is it’s taken as-is, so a shift amount of zero will either double or zero out the current frequency value on channel 5. So there’s that.

While trying to determine that, however, I noticed an odd behavior. A little experimentation shows that there’s not one, but two actual bugs in the hardware implementation of the sweep function!

By design, the sweep function will stop channel 5 if the result of the sweep operation would cause its frequency value to exceed 2047. No harm there, but the failsafe still shuts off the channel even if the sweep function is not active (either disabled in the control register or if the sweep interval is zero). Logically, one would think that the channel should only activate if the sweep function is actually turned on.

Additionally, channel shutoff happens one sweep frame early. The algorithm looks something like this:

• Calculate the new frequency value = current ± (current >> shift)
• If new value > 2047, stop channel
• Wait for the modification interval to elapse
• Update the current frequency value with the new one
• Return to top

It might be hard to see why that’s a problem, so let’s try a for-instance. Let’s say we use frequency value 510, which comes out to about 101.6 hz for a full wave, and a sweep shift amount of zero, which will double the frequency value every sweep frame.

• During the first frame, it notices that 510 * 2 = 1020 is less than 2048, so it plays the frame at 510 then sets it to 1020 afterward.
• During the second frame, it notices that 2040 is less than 2048, so it plays the frame at 1020 then sets it to 2040 afterward.
• During the third frame, it notices that 4080 is greater than 2047 and stops the channel.

So even though 2040 is a valid frequency value, the channel was stopped without playing at that frequency.

I was a doofus and forgot to initialize PCM wave memory on startup. In the build attached to the OP, you’d have to change all the zeroes to something else and back to zero for it to take effect.

Attached to this post is a fixed version.

Attachments:

The photo in the article has the stand on backwards. O-:<

The intensity of each shade of red is not a fixed brightness–it can be configured by the software independently for each of the three shades (with some exception regarding the brightest shade). That said, there are effectively 128 evenly-spaced different brightness settings, with 0 being black and 127 being full-intensity red.

Where the brightness intensity value i is some number from 0 to 127, the corresponding RGB value can be calculated as follows:

rgb(round(i * 255 / 127), 0, 0)

Lester Knight wrote:
i’m assuming the programmers tossed in the english alphabet in the hopes of a possible future north american release?

Full-width Latin characters are extraordinarily common in Japanese character sets, not in small part because of the fact that English is used a ton in technical settings. Having said that, full-width characters generally aren’t too useful for English localization, and I’ve seen many cases where brand new graphics were put in to accommodate half-width or variable-width English scripts.

Though I have to say, the presence of a cursive alphabet does make me curious.

I’ve decided that even though I can’t draw good pictures, I’ll just have to find a way to make the game with sucky pictures instead. (-: I mean, really, think of some of the simpler cartoons you’ve seen. Do they not work well even with sucky graphics?

Look at that thing. It’s a circle with a rectangle for a body. If Craig McCracken could make The Powerpuff Girls out of that, then I gosh darn better be able to do something… I’ll have to think on it and see what I come up with.

Guess I’d better start fleshing out the details of the game, then. They look like they’ll come into play sooner than expected.

cr1901 wrote:
What’s the difference between FRAMESTART and XPEND? I was confusing the two, and in fact if I sync to FRAMESTART (at which point, VIP calculations should occur), virtually nothing gets drawn to the screen. Are the display buffers locked while the VIP is doing calculations?

FRAMESTART occurs at the beginning of frame operations. I trust you know the difference between a display frame and a game frame–FRAMESTART applies to display frames. Assuming you’re using 1 display frame per game frame (FRMCYC = 0), then FRAMESTART will also signify the beginning of drawing operations every time it’s thrown (otherwise, use GAMESTART). In this situation, writing to the framebuffers will just cause your data to be overwritten by the VIP when it carries out its drawing routines.

XPEND is thrown at the end of the VIP’s drawing routines, when it is no longer using character, map, object or window memory. Most software should use this interrupt condition to synchronize program flow with the display rate (50 times per second). If you’ll be writing to the framebuffers yourself, now’s the time to do it.

Whether framebuffer memory is locked during the drawing procedure, I haven’t tested it. Do some profiling for science!

cr1901 wrote:
I set: WA[31].head = WRLD_END;, so the amount of time taken for the VIP to draw should be trivial […]

My brain says that this should work, but make sure you’re syncing to the XPEND interrupt.

It’s important to remember that even when all windows are disabled, the VIP still writes to the framebuffers because of the clear color (set by BKCOL). Maybe this is what you want, since it gives you a blank slate and you don’t have to update every pixel in the image yourself.

If you don’t want the VIP messing with the framebuffers at all, simply disable drawing (XPCTRL.XPEN). Having said that, while I haven’t looked too deep into it, I seem to remember that the front/back bit for which framebuffers to scan doesn’t toggle each frame unless drawing is enabled, meaning you’ll have to write to the same left/right framebuffers every frame (I think the default is 0, at bus addres 0x00000000).

Of course, if you do disable drawing, then the XPEND interrupt will never be raised. In this case, FRAMESTART is the one you want.

I’m glad my idea was well-received, even if I couldn’t elaborate on it a whole lot. (-: It means a lot to me!

And I’m a bit conflicted. I’m not really at a point where I can put a lot of time into such a game, so I’m not all that gung-ho about making it in the near future. But if I don’t, then I’ll be sitting here on the lore all by myself thinking, “I bet this would be a powerful narrative if only I could share it with someone.”

So here’s what I’m willing to do… First, ask yourself if you really want the story spoiled up-front, or wait until such a time that the game comes to fruition. To draw a parallel, think of The Sixth Sense, where Bruce Willis’s character was dead the whole time (spoiler alert!). Now imagine if you knew that the first time you saw the movie… If you’re still morbidly curious about whatever this oh-so-amazing plot point is that I keep talking about, shoot me a PM and I’ll tell you.

For everyone else, I’ve got a few more YouTunes links–mostly from my Chiptunes menu–showcasing some of the aesthetics I have in mind:

Mythology/Creation: Alinos #2 – Metroid Prime Hunters
Mood (potential in every moment): Godisregn – Malmen and Zalza
Mood (a fine day for success): Mind of a Dreamer – BeaT
Mood (destiny is what we make of it): Sunstreak – Radix
Mood (the things I want to do): Sunny Hollow – Wiklund
Mythology/Reminiscence: “Wapod” – Kirby’s Adventure Wii

  • This reply was modified 11 years, 2 months ago by Guy Perfect.

I’ve been mulling over an idea for a game this last week, but again the story is one of those “don’t spoil it until the big reveal” things, so I can’t really say what makes it so great! )-:< But hey, a marketing blurb wouldn't hurt: __________ Name: To Exist
Genre: Probably RPG, but if not, then vanilla adventure
Synopsis:
There you are. Others are here with you, but there isn’t anything here, and no one can remember what happened prior to right now. Slowly, the world begins to take form, and you and the others can craft it into just the kind place you’d like it to be. But a sense of dread starts to cover the land when you come across some people who claim to know what’s going on. Seemingly immortal, they tell you that universes come and go periodically, and only they are protected from the oblivion that will overcome everything you’ve ever known. Not all hope is lost, for there is a way to persist yourself! How can you survive? What will happen to the world, and when will it end? Who is the mysterious figure that the events of the world seem to focus on?
__________

Sounds pretty grim at a glance, right? But the tone of the game is exactly the opposite: it’s full of looking for the potential in every moment and making your dreams a reality. The fact that the universe is doomed to erasure stands as a stark contrast to the bright outlook of the content at large.

As a citizen of this otherworldly realm, you have the power to conjure up manifestations of your own ideas and implement them into the world. This requires a sort of power source from a free-floating form of energy that naturally coheres into non-sentient organisms known as Figments. When you defeat a Figment, its energy becomes your own, and you become empowered to create in proportion to the energy absorbed. It’s through this means that you and the others create the world at the dawn of time, and through this means that the events of the game transpire.

Departing from traditional territory, this story is not one of good-versus-evil as so many games tend to be, nor is it one of survival-of-the-fittest. It’s a tale of understanding, and coming to terms with the notion that everything you’ve ever worked for may one day be lost–the importance of focusing on what matters most… whatever that is. Nonetneless, the game still has an extraordinarily uplifting mood, as everyone you encounter has their own hopes and aspirations, and through Figment energy, everyone can work to make their dreams come true. The game straddles the border of hope and despair, and your character sets out on a quest to discover the truth of exactly what’s going on… and find out what can be done about it.

The game plays in a sort of episodic way: you travel from place to place interacting with the local populous. You listen to their stories, go on adventures with them, and solve mysteries together. As you progress, you start to pick up on the true nature of the world, but as your understanding grows, the amount of time you have left shrinks. In your travels, you learn of individuals who existed before you did: people who originated in some prior universe and are somehow immune to the destruction at the end of all things. These individuals, known as Immortals, are your best bet to learning the truth, as well as learning why they never vanished when the rest of their worlds did.

At the pinnacle of mystique is an individual the Immortals refer to as “the Subject”. They don’t seem all that different from anyone else, but they can manifest their ideas without Figment energy and apparently have the ability to travel through time… it’s hard to say, really. But if the Immortals think highly of the Subject, then there are probably more answers there.

Since the game is largely a web of interconnected sidequests, there is no one route you can take through the storyline. The choices you make–the places you go and people you interact with–influence the progression of the game and state of the world at large. This will hopefully lead to greater replay value because A) you don’t necessarily get all of the content after the first time or two through the game, and B) there’s ample room for experimentation to see just how much you can experience in a single playthrough (or the most efficient way to do everything).

Completing the smaller story arcs awards you with tokens of a sort that you can put towards improving your character. This directly encourages exploration and meeting lots of other characters in the game, as you don’t get to win by simply hitting the major plot points: you’ll be too weak to advance to more challenging content (and there’s no experienced-based level-up system here). Instead, take your time to have a look around and you’ll be much better off because of it.

I’m still toying with ideas for mechanics. I have some ideas for how character build and abilities will work, but nothing is set in stone just yet. The open-ended structure of the game means it’s very possible that it can be implemented as a 2-player RPG, where players can pop in and out of another’s game at any time without upsetting their own. I’m even trying to see if I can come up with a way for two linked systems to contribute to a larger, simultaneous world to experience the game in. The system has a link port, doggonnit, and it’s my civic duty to make use of it.

While I don’t have eyeball precision on the millisecond level, I can at least convey what I’ve picked up from the documentation. Whether this is 100% correct remains to be seen, so make of it what you will. (-:

cr1901 wrote:
Drawing occurs between points 4-6 and 8-10. Am I supposed to interpret 4-6 and 8-10 as “the same LED array being powered on twice”, or “the left LED array is powered from 4-6” and “the right LED array is powered from 8-10”?

[…]

On the same token however, the same page states that the mirrors oscillate 180 degrees out of phase. If the graph is a composite of both mirror movements, this seems to imply that the mirrors are NOT out of phase- just that the LEDs are triggered while one mirror is moving in one direction, and while the other mirror moves in the opposite direction.

It is my understanding that the left display is scanned first, followed by the right display. A high-speed camera can probably verify this.

The mirrors oscillate with a half-period offset to maintain physical balance: Newton’s first law comes into play and prevents the device from tipping over. While the specifics of the scanning hardware are a mite foggy, I get the impression that scanning only occurs during the same motion on each mirror, meaning one display is scanned before the other.

cr1901 wrote:
I wish to time a gfx routine that I wrote, and I want to synchronize it to not necessarily what the VIP thinks is the start of a new frame, but the time immediately after the LED array turns off and the mirrors start slowing down to reverse direction- i.e. what the scanner/mirrors think is the “start of the time where it’s safe to draw”.

The VIP interrupt registers at 0x0005F800, 0x0005F802 and 0x0005F804 actually accommodate this out of the box: bit 14 (0x8000) occurs when the VIP finishes drawing to the framebuffers (meaning it’s safe to reconfigure characters, windows and objects before a frame is actually displayed), and bit 2 (0x0004) occurs when the right display has finished scanning (something you’ll need to know when writing to the framebuffers yourself).

Yeowch, when you’re laying in bed for days to rest an inflamed neck muscle and it still hurts, that’s no good. And then you get up and go to work and you get to use that muscle all day long to hold your own dang head up. Needless to say, this week could have been more comfortable!

Remember when I mentioned that I have the audio project so figured-out that I won’t be making further changes at this point? Recall that being a thing what was once said?

Guy Perfect wrote:
[…] I feel quite firmly that I’ve got the specifics down to the point that I won’t really be making them any better through further revisions, so I’m ready to make an announcement…

Okay, so that’s still technically true. The specifics of the audio architecture, the data format and all the many musical features haven’t changed. I’ve just been second-guessing myself on the implementation.

See, I don’t like brute force algorithms as a rule. On large data sets, they’re very slow. So when I started implementing these audio libraries, I knew I’d be looking at an array of objects, where any given one of them might be active or might be available for use. But instead of scanning through the array from the start, checking each object to see whether it was available, I implemented a sort of automated memory manager that operated in O(1) time to fetch the next available object. And it was beautiful.

Then, when implementing music notes and event lists for the music project, I noticed that the link information to maintain object status like that was taking up a lot of bytes per object. And there’s some pretty esoteric code driving the whole thing. And then I had to implement something very similar on top of that so event lists could terminate their child lists and notes when they themselves ended, and the memory usage started to bloat. I kept telling myself, “Look, there’s only going to be like 5 to 10 notes playing at a time, so it’s not like the system is going to run out of memory.”

Of course, I started listening to myself. If we’re talking about collections of 5 to 10 elements, then what would otherwise have been a speed boost granted by the memory management routines no longer saves any time because 10 elements doesn’t take time to begin with. So all I’m left with in its place is some confusing code that operates on a lot of bytes in memory, and frankly, I think that’s a bit overkill.

I’m currently analyzing the architecture to see what kind of speed and memory impact a brute force approach would have. So far, I’m thinking it’s going to be both a lot more streamlined, easier to work with (the source is going public, after all), and in the end not be any slower than the first way I was doing it.

Yet another rewrite is around the corner, but at least it’s only a small part of the greater whole. (-:

Turns out I accidentally nerd sniped myself this week. Productivity dwindled as a result. On the bright side, it provided great clarity, and most importantly, it allowed me to come to a decision on how to proceed. (-:

Allow me to provide some background…

Event Lists and Envelopes operate on one of two time scales: realtime or “beats”, which is based on the master tempo. Realtime is simple: it’s just some number of milliseconds. But beats posed an interesting problem because at any given time, the master tempo can change, thereby changing the relationship of milliseconds-to-beats when processing other beats-based events… Okay, so it’s kind of hard to explain. Let’s try a for-instance.

Generally speaking, when writing music, you’ll be using the beats time scale because that’s the whole point of including the tempo mechanic. When Mario’s timer reaches 99 units remaining, the music picks up speed to express a sense of urgency. That’s accomplished with an increase in tempo. Music notes are almost always going to be built around beats: their timestamps and durations need to be synchronized with all the other notes according to the tempo.

Individual Envelopes on a Note can use either time scale, and in many cases you may opt to use both. What’s an envelope? It’s a sort of graph over time that modifies a property of a note (or Event List, or the master Tempo), including volume, pitch and panning:

* If you’re going for a piano sound, for example, there will be a very brief period of high volume followed by a prolonged period of lower volume that gradually tapers out. That’s a good example of when you’d use a realtime-based Envelope. If the attack period takes too long, it won’t sound right, and you don’t want that to be influenced by the tempo of the track (such as if the music slows down).

* If, on the other hand, you want to express some artistic flair in line with the rest of the composition, you may need to adjust volume to make, as an example, the note of a distorted guitar gradually fade out just as another part of the music begins. This would be a situation where you would use a beats-based Envelope.

* Perhaps the same note needs both an attack/decay component and a song-synchonized fade component. If that’s the case, then you can use both time scales on the same Note.

… And that’s the background.

While processing Event Lists each audio frame, starting positions and durations of Event Lists, Notes or Envelopes needs to be relative to how much of the audio frame has actually been processed in the scheduler. For example, if two thirds of an audio frame “elapse” before a Note is played, then the duration of that note needs to be shortened by the remaining one third of the time in the audio frame that haven’t been processed yet. Otherwise, the Note would start too late and end too late.

The first solution was awfully simple: just calculate at the beginning of the audio frame how many milliseconds and beats are actually occupied by that frame and process each Event List, Note and Envelope accordingly.

But then it hit me: while processing Event Lists and Envelopes, the tempo can actually be changed in the middle of frame processing. That would affect how many beats-per-millisecond are occupied by the remainder of the audio frame. What’s the most accurate way to handle that?

Well, it gets kind of complicated after that. I came up with a dozen ways it could hypothetically work, and all of them took a depressingly large number of operations to work out. So I made a call and will be going forward from here:

The first version of the tracker will not reflect changes to tempo during the processing of a single audio frame: the changes will take effect at the beginning of the next frame. This allows the implementation to use my original idea: just calculate the time elapsed up front and use it through the whole frame processing.

I really don’t think that’ll be an issue because audio frames might be something like 80 times a second. Do you really need your tempo to be able to change more than 80 times a second? If it did, would you even be able to tell? I sure as heck couldn’t; the video frames themselves only happen 50 times a second.

I’m glad you guys are looking forward to it. I’m working on it every day and the scent of done-ness is growing stronger and stronger. (-:

DogP lent his electronics expertise once again to solve an interesting little hardware anomaly I ran into. See, the VSU outputs a digital signal where the minimum sample value is 0 and the maximum, if all six channels are outputting their maximum samples at full volume, happens to be 684. Since no negative samples come out of the unit, the audio streams look something like this:

“Surely,” I thought, “this isn’t actually what gets sent from the unit. It’d fry the speaker!” And sure enough, it didn’t look like it gets sent verbatim to the speakers. I recorded some audio output from the Virtual Boy and noticed the resulting wave form was… well, it kinda curved a bit. Still effectively the same audio, but somehow or other it automatically flexed itself to balance around +0V. So I asked DogP what was going on.

Since I’m somewhat less than a noob in terms of electronics, I had no idea it was a simple matter of something called capacitive coupling, wherein a capacitor and resistor are used to block any constant DC voltage from a signal before passing it onto another circuit. The long and short of it is that it’s an implementation of the simplest-possible high pass filter with a very low cutoff frequency, and the effective result is that it removes the DC offset of a stream.

Fortunately, since this is just a first-order filter where the only wiggle room is the cutoff frequency itself, I was able to implement it in the Java VSU emulator without issue and now my output is effectively identical to the clips I was capturing from the hardware:

So score another point for accuracy in emulation. (-:

I’m feeling particularly artistic this time around. <3