Original Post

I want to learn how to program sound for the VB. Does the Virtual Boy have a set of sounds it can play and all you have to do is call them up, or is it much more difficult? Even so, I would still want to learn just how to do this. I want my games to have sound. I am musically inclined, so I can compose some songs if need be.

34 Replies

Well, you can look at gccVB’s audio.h file, and you can use the VSU register map

http://www.planetvb.com/modules/dokuwiki/doku.php?id=vsu_register_map

to get an idea of what is what.

I’ve asked about sound before, but got no answers. It’d be nice if someone who knows about sound programming would share their knowledge.

Unfortunately, no, it’s a lot harder than just calling up built-in sounds. I’ve never done it, but from looking at the programming manuals, my understanding is that the VSU (Virtual Sound Unit) has a number of registers which can be programmed with a very short “sound effect”. (The “sound effect” is actually a wave pattern which defines an “instrument” of sorts.) It also has other registers which tell the VSU if the sound should be played, how fast it should be played (the frequency, or pitch of the sound), how loud it should be played, etc. This is mostly for making music though… To actually play sound effects, there are a few different techniques. One is to use the standard “instruments” (channels 1-4 of the VSU) to play beep boop sounds, use the sweep channel (channel 5 of the VSU) to make “boing” jumping noises, or use the noise generator (channel 6) to make explosion noises. However, DogP also wrote a demo/utility for converting wav files into a format that could (with some supporting code) be played on the VB. I just tried it, and in mednafen the default code seems to be playing the sound files too fast, (in fact, exactly 10x too fast!) but I just got it to work by changing the the definition of SR_DIV on line 126 of wavonvb.c to 3750000 instead of 375000. Beware though, that including wav files in your game will significantly increase the size of the ROM image. That demo with just the four sound files requires an 8Mbit cartridge! Hope this helps!

That’s what I want to do: Make music. I played with the wav converter, but it seems like the game freezes while playing the file (you can’t press a buton or anything.)

interesting! if someone could give an example of code to make music or sounds would be great!!!!

VirtualChris wrote:
That’s what I want to do: Make music. I played with the wav converter, but it seems like the game freezes while playing the file (you can’t press a buton or anything.)

It’s a good learning experience to try and understand what other people’s code is doing. I think you mentioned that C isn’t your first programming language VirtualChris, so a couple of good coding exercises would be: Can you see why the game “freezes” while the sound is playing? Can you make it so that the currently playing sound stops when a button is pressed?

Unfortunately, we don’t have any good utilities right now for converting something like a midi file to a format the VB can play. (At least not any released ones… *cough*DanB*cough ;-)) DogP’s wav player really isn’t a practical way to play music during the game. The practical way to play music during the game is to use the VB’s built-in tone playing capabilities along with something like a timer interrupt, so that the speed of the game doesn’t affect the pitch of the sound, and the sound doesn’t freeze the game.

rubengar wrote:
interesting! if someone could give an example of code to make music or sounds would be great!!!!

Precisely. All I want is an example of how to program the VSU registers to generate tones and effects. I don’t care whether they freeze the game or not.

HorvatM wrote:

rubengar wrote:
interesting! if someone could give an example of code to make music or sounds would be great!!!!

Precisely. All I want is an example of how to program the VSU registers to generate tones and effects. I don’t care whether they freeze the game or not.

It really is as simple as writing to the VSU registers and RAM periodically (such as with the timer interrupt, as you said). But, if you want example code, just run the included example file (test.txt) through DogP’s Virtual Boy Sound Generator and tell it to output VB source along with the WAV file. You can even use it to experiment with the sound registers and hear what it sounds like without the full compile(/program cart)/run cycle.

After you get that, it’s pretty much just figuring out how all those registers and wave patterns affect the sound. Anyone familiar with how digital sound reproduction “works” (especially with regard to basic additive synthesizers like the VSU) and/or has some musical talent: feel free to write a tutorial on that topic for the wiki!

  • This reply was modified 11 years, 8 months ago by RunnerPack.
  • This reply was modified 11 years, 8 months ago by RunnerPack.

OK, so I put in the example.txt included and it spat out some VB code. I go to put it in my game, and it spat out a huge list of errors. So I change the top line to “#include modlibgccvb.h” and it gave me a much more managable error list. Only trouble is, I don’t know what any of this stuff means.

EDIT: OK, figured it out.

Attachments:

I can explain more later, but if you want to get started on making sound, pull up the code to Super Bounce. That is probably one of the most basic implementations of it.

What you have to wrap your head around when using this is that you’re programming the frequencies, not samples. Where in a wav file, you’re outputting each sample, and have to keep updating the sample or no sound comes out… with this, you can set the frequency to 1000Hz, and never touch it again and it’ll keep playing.

For a quick start guide: SxFQL and SxFQH are the frequency registers (together they’re 11 bits of frequency), SxLRV is volume for left/right (4 bits each), SxEV0 is the envelope register, which you should keep at 0xF0 for simplicity (sort of a master volume as well when not using other features). SxINT you should set to 0x80 to start playing, 0x00 to stop. And SxRAM selects which waveform RAM you’re playing from… I’d set it to 0 (you should actually fill the waveform RAM, but it still plays sound without doing it). If you want to stop all channels, set SSTOP to 1. I’d only mess with SND_REGS[WAVE1] to begin with.

Hopefully that’ll get you going.

DogP

Thanks!

I’m having some difficulty though. My libgccvb’s audio.h is a bit different:

typedef struct SOUNDREG
{
	u8 ctl;
	u8 spacer1[3];
	u8 vol;
	u8 spacer2[3];
	u8 fql;
	u8 spacer3[3];
	u8 fqh;
	u8 spacer4[3];
	u8 env;
	u8 spacer5[3];
	u8 unk;
	u8 spacer6[3];
	u8 ram;
	u8 spacer7[3];
	u8 spacer8[36];
} SOUNDREG;

Which register is which? I’m assuming ‘EV0’ is ‘env’ and ‘INT’ is ‘ctl’. What I’m trying to do is this:

int main ()
{
  unsigned int Freq;

  SND_REGS[WAVE1].ram = 0;
  SND_REGS[WAVE1].vol = 0x66;
  SND_REGS[WAVE1].ctl = 0x80;

  while(1)
  {
    for(Freq = 0; Freq <= 1000; Freq++)
    {
      SND_REGS[WAVE1].fql = (Freq << 4) & 0xFF;
      SND_REGS[WAVE1].fqh = (Freq >> 4) + 1;
    }
  }
}

Check the libgccvb.h included in Super Bounce… they’re defined like:

u8 SxINT;
u8 spacer1[3];
u8 SxLRV;
u8 spacer2[3];
u8 SxFQL;
u8 spacer3[3];
u8 SxFQH;
u8 spacer4[3];
u8 SxEV0;
u8 spacer5[3];
u8 SxEV1;
u8 spacer6[3];
//Ch. 1-5 only 
u8 SxRAM;
u8 spacer7[3];
//Ch. 5 only
u8 S5SWP;
u8 spacer8[35];

DogP

Nothing changes.

I think you do need to fill the waveform RAM to get sound?
At least in Mednafen…

Anyways, maybe it’s time to share a little 🙂
Here is a basic function from my midi player that plays a single note:

void PlayNote(u8 chan, u16 freq, u8 vol) {
	//Set up the frequency the channel will play
	SND_REGS[chan].SxFQH = freq >> 8;
	SND_REGS[chan].SxFQL = freq & 0xFF;

	//Set the volume for the channel (0-15, same for left/right)
	SND_REGS[chan].SxLRV = (vol << 4) | vol;

	//Envelope for the channel (makes the tone fade out)
	SND_REGS[chan].SxEV0 = 0xF7;
	SND_REGS[chan].SxEV1 = 0x01;

	//Start the channel without interval
	SND_REGS[chan].SxINT = 0x9F;
}

Usage:

#include "audio.h"
#include "notes.h"
#include "voices.h"

//Copy the piano "instrument" to soundbank 1
copymem((void*)WAVEDATA1, (void*)PIANO, 128);

//Tell channel 0 to use soundbank 1
SND_REGS[0].SxRAM = 0;

//Play a "Middle-C" note on channel 0 with volume 8
PlayNote(0, C_4, 8);

The file "voices.h" includes a couple of different "instruments" that I made, to be loaded into the soundbanks.

The file "notes.h" defines all standard notes, fine-tuned manually to fit the VB's frequencies.

This should help you to get some tunes flowing 🙂
Just call PlayNote() with different note values (E_4, D_4, G_4 etc.) within your main loop (or better, on a timer interrupt)

  • This reply was modified 11 years, 8 months ago by DanB.
Attachments:

Wow, that’s great! Actually the only thing DogP wasn’t clear on are the envelope registers and the waveform register. Now that I see how your PlayNote function works, it all seems really simple. Thank you once again!

Unfortunately, your PlayNote() doesn’t show tempo, and if it did, wouldn’t it take a long time to get a complex song on there?

It wouldn’t be too difficult to write some code to read a music track from an array and play it at the right speed. Getting it to play in the background, however, is another thing.

Well, it’s up to you to decide the tempo by controlling how often you call PlayNote()…

To play a simple song, you can do something like:

u16 song[] = {C_4, D_4, E4, FS4, A_5};
u32 songTick = 0;
u8 currNote = 0;
while(1){
  //Playing the song in the background is easy,
  //just control its tempo by only calling playnote every
  //57:th (or whatever) pass through the game loop
  if (songTick == 57) {
    PlayNote(0, song[currNote], 8);
    currNote++;
    if (currNote > 4)
      currNote = 0;
    songTick = 0;
  }
  
  //Do other game-stuff

  songTick++;
}

For more complex song playing, you’ll have to wait some more for the full midi player 😛

  • This reply was modified 11 years, 8 months ago by DanB.

Where do I get vsu.h?

VirtualChris wrote:
Where do I get vsu.h?

here you have it! do not get it to work: (

DanB wrote:
Well, it’s up to you to decide the tempo by controlling how often you call PlayNote()…

To play a simple song, you can do something like:

u16 song[] = {C_4, D_4, E4, FS4, A_5};
u32 songTick = 0;
u8 currNote = 0;
while(1){
  //Playing the song in the background is easy,
  //just control its tempo by only calling playnote every
  //57:th (or whatever) pass through the game loop
  if (songTick == 57) {
    PlayNote(0, song[currNote], 8);
    currNote++;
    if (currNote > 4)
      currNote = 0;
    songTick = 0;
  }
  
  //Do other game-stuff

  songTick++;
}

For more complex song playing, you’ll have to wait some more for the full midi player 😛

One question, as define the duration of each note??? thanks for help me!!

 

Write a reply

You must be logged in to reply to this topic.