Issues to play sound effects with SNESMod

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Issues to play sound effects with SNESMod
by on (#209963)
Hi again,

Now that the graphics issues of my game project are fixed thanks to you, I've another big issue related to the audio part .

I use PVSNESLib, which is bundled with the wonderful SNESmod library to play sounds and music. I've got an hard time to figure out how to effectively use all those functions, so I may have made newbie mistakes, but, for now:
- I can get a music to play back perfectly (SNESmod is great!)
- I can get sounds effects to play back too, with several issues, detailed below. To play the Sound Effects, I defined a soundbank (of BRRsamples), and during the game I use the Playsound(#sfxID) function to play them back.

Here are my current issues:

1) Only one Sound Effect can be played at time. Each time I call "PlaySound()", it stops the currently playing sound effect, to play the new one. As Skipp and Friends (the only game I know to use SNESmod too) shows a similar behavior, I guess it's normal. But the SNESmod source shows that it can apparently plays 2 samples at the same time when streaming is disabled, although I'm unsure how to do that.

2) Besides that, my Sound Effects plays fine on every emulator, in 60Hz mode. But, when I play my game in 50Hz mode, either on my PAL SNES or in BSNES, most of the sounds samples are "screwed". Sometimes they plays OK, other times they are crackling, glitching or delayed. Indeed, as only one sound can play at a time, my SFX often "cut" each other. On 60Hz, that's not a problem, but in 50Hz, sometime the second sound is played while remnants of the first (interrupted) sound are also played.

I've contacted Mukunda, who was super helpful. He told me that the streaming timings are designed for 60Hz consoles, and not 50Hz ones. The music however plays smoothly both in 50Hz and 60Hz mode, only the sound effects are distorted.

3) I don't understand how to use the "LoadEffect / PlayEffect" functions. Which is too bad because they seem to be a "non-streaming" option to play samples, that could solve my 50Hz issue. Despite my many tries, I can't them to play any of my sound effects. First, I've defined my SoundBank will all the Sound Effect parameters. Then, I use "spcLoadEffect(#sfxID)", wait a bit, then use "spcEffect(pitch, #sfxID, vol*16+pan)". But all I can get with this method are strange "beeps" instead of my sound sample.

Do you know how to effectively use these functions to play Sound Effects?

Regarding memory, during gameplay, I only have about 20KB of Sound Effects (after BRR conversion) and 13KB of music (after SNESMod conversion), so I guess they should all be able to fit inside the SPC memory.

For now, the only critical issue is second one, as it renders the game unplayable on a PAL SNES. On a NTSC one, it's OK even with one sample at a time, although 2 samples at a time would obviously be better if possible.

Do you have any hints or ideas on these issues?

Thanks again a lot for your help!
Re: Issues to play sound effects with SNESMod
by on (#210077)
This is where my seven to eight years of experience with this sound driver comes into play (I've known this sound driver since near the beginning).

Interesting. The sound driver has a partial incompatibility with PAL. I have some ASM ideas to try to fix this... namely fooling around with the number of BRR blocks the SNES sends over to the SPC700 per frame. I actually started thinking about this with my own sound driver idea: namely that I would have to account for that difference myself.

These numbers don't quite come out even in some cases, but I'll give it a go...

All of the changes I'm requesting apply to snesmodwla.asm. I did the original conversion from ca65 to WLA back in 2012, actually! alekmaul then updated my original conversion from there. :D
Here's the original set (found on line 1241):
Code:
digi_rates:
   .db   0, 3, 5, 7, 9, 11, 13


Since a PAL SNES runs at five sixths the framerate, these should be updated to at least these values:
Code:
digi_rates:
   .db   0, 4, 6, 9, 11, 13, 16

In reality, I got 0, 3.6, 6, 8.4, 10.8, 13.2 and 15.6. I rounded all of them up except for 6, which was an exact result.

On that note, here's line 65...
Code:
.define INIT_DATACOPY 13

Change that to a 16...

...and line 64...
Code:
.define PROCESS_TIME 5

Change this to a 6.

This is just simply to scale it to PAL timings. It's not quite exact numerically speaking (except for 5 turning into a 6), but it should give better results.

Oh, and did you say you have a 13KB module and 20KB of SFX samples? Going by a general estimate, that certainly fits inside the SPC700 (plus the filesize of the SNESMod program itself).

First, when using Load Effect, make sure to load the samples after you've loaded the module. Otherwise they'll be overwritten by the module data. If you want them to be loaded in one go and then load no more samples, use the module that takes up the most space on the SPC700, load that module, load the sound effects, then load any module you want after that point. The sound effects will stay put without being overwritten.

Second, there's a quirk with Load Effect: it uses sample IDs from the soundbank rather than actual pointers. The soundbank export option does not give you pre-defined sample IDs from the modules that you export, so on my end, I make sure that if I add any SFX, then they're the first ones to be added to the soundbank so that I can have a sense of consistency with the sample IDs. There is an alternative to this: you can just simply put the SFX in their own soundbank, but you still need to put them in a module. The module itself can allow you to test the samples themselves before trying to load them as sound effects somewhere else.
Re: Issues to play sound effects with SNESMod
by on (#210133)
Woaw, again, thanks a lot for your very precious help KungFuFurby!

I'll try to modify the asm source following your direction to allow for PAL-compatible timing of the sound streaming system, but it'll be even better if I can get the LoadEffect() / PlayEffect system to work (because no streaming = no timing issues, and also two channels instead of one!).

I was actually loading the music first, but the sound effects just after them: I guess I'll need to wait several Vblanks before loading sfx. I also guess I have to send them one after the other (I was "bulk-sending" them all), and I'll try to load my largest song first to follow your directions.

I'll keep you updated with the results of all this, but thanks again a lot for your help! :)
Re: Issues to play sound effects with SNESMod
by on (#210191)
This is good timing, I was just making updates to smconv and sneskit. I've added the KungFuFurby's suggestions for PAL to SNESKit which will be used if PAL is defined.
Re: Issues to play sound effects with SNESMod
by on (#210257)
KungFuFurby wrote:
Second, there's a quirk with Load Effect: it uses sample IDs from the soundbank rather than actual pointers. The soundbank export option does not give you pre-defined sample IDs from the modules that you export, so on my end, I make sure that if I add any SFX, then they're the first ones to be added to the soundbank so that I can have a sense of consistency with the sample IDs. There is an alternative to this: you can just simply put the SFX in their own soundbank, but you still need to put them in a module. The module itself can allow you to test the samples themselves before trying to load them as sound effects somewhere else.


I'm still struggling with to use LoadEffect, but after reading your message, I start to feel that maybe the way I include the sample is wrong. For now, to add audio in my game, I use:

- SMCONV to convert the IT to a "soundbank" format (it generate a soundbank.bnk (binary data), and soundbank.asm (include to add the binarydata in the rom) and soundbank.h (export variable to load the module in C code)

- BRRtools to convert the Wav sfx samples to .BRR files. I then include each BRR binary file manually into to the rom using my data.asm file. Last but not least, in C code, I build a "samples soundbank" using spcSetSoundDataEntry(), that will generate a struct (BRRsamples) holding the sample parameters (BRR adress and length in the rom, volume, pitch, etc.). I build a "struct" for each BRR sample I have, and they are declared one after each other during var decalaration, so they are all one after the other in the memory too. So, I'm calling spcSetSoundTableEntry(&BRRsamples#1) to tell SNESmod that the beginning of my "sound table" is the first BRRsamples struct. That way, I can play "streaming" sound effects using spcPlaySound(id), where ID in the index of a BRRsamples struct to play.

When I use LoadEffect / PlayEffect with the id I defined this way, all I can get are "beeps". But I wonder: do I actually have to include the BRR samples directly in the "soundbank" generated by SMCONV so they can be played by LoadEffect?

If yes, how can I do that?
(SMConv only takes it files for input, not Wav or BRR samples)

Thanks again for your help!
Re: Issues to play sound effects with SNESMod
by on (#210311)
drludos wrote:
When I use LoadEffect / PlayEffect with the id I defined this way, all I can get are "beeps". But I wonder: do I actually have to include the BRR samples directly in the "soundbank" generated by SMCONV so they can be played by LoadEffect?

If yes, how can I do that?
(SMConv only takes it files for input, not Wav or BRR samples)

Thanks again for your help!


That is confirmed. Including the .wav samples in an IT file and sending it to SMCONV to make a soundbank is how to use them wtih LoadEffect.
Re: Issues to play sound effects with SNESMod
by on (#210342)
KungFuFurby wrote:
That is confirmed. Including the .wav samples in an IT file and sending it to SMCONV to make a soundbank is how to use them wtih LoadEffect.


Thanks for the explanation, now it's clear to me the difference between spcEffect (load from the IT soundbank) and spcPlaySound (stream from anywhere in the game rom).

I have one last question: how do I need to include the wav sample in the IT file to have it recognized by SMCONV / SNESmod?
- Do i simply add the sample I want to play inside an empty IT file? In this case, can I add all my wav samples inside a single IT file?
- Or do I have to create a track in the IT file where the sample is played once (i.e. a single note that plays the sample), and that's what will be actually played by SNESmod?

Thanks again for your help - I never could have figured this out without your answers!
Re: Issues to play sound effects with SNESMod
by on (#210555)
drludos wrote:
I have one last question: how do I need to include the wav sample in the IT file to have it recognized by SMCONV / SNESmod?
- Do i simply add the sample I want to play inside an empty IT file? In this case, can I add all my wav samples inside a single IT file?
- Or do I have to create a track in the IT file where the sample is played once (i.e. a single note that plays the sample), and that's what will be actually played by SNESmod?


You can load all of the WAV samples inside an empty IT file if you want.
Re: Issues to play sound effects with SNESMod
by on (#211790)
Hi again KungFuFurby,

Sorry for the late reply, but between work and real life, it took me longer than I expected to test all your solutions!

To keep it short: thank you A LOT, because it now works perfectly!

Following your instructions, I've finally been able to play sound effect from the SPC RAM, using "spcEffect", and not the streaming functions. Doing so resolves all the issues of the 50hz/60hz timing differences when the lib is streaming a sound. With spcEffect, the sound play back perfectly both on PAL and NTSC consoles - no more distortion or mixed sounds.

I also got my SNES modded (50/60hz switchless mod) to be able to test both version on real hardware, and it works great on an actual SNES too.

I also confirm you that, when using SNESmod's spcEffect, you do have 2 channels available to play SFX (channel 7 and 8). If you use streaming by calling spcPlaySound, it'll use the channel 7 for streaming, leaving only channel 8 for spcEffect. In case of conflict, the non-streaming functions seems to have priority over the streaming one:
- If you play a streaming sound, and trigger two non-streaming sounds, the streaming will be cut off immediately so the two non-streaming sounds can play.
- If you play two non-streaming sounds, and trigger a streaming sound, it won't be played, unless at least one of the non-streaming sound has finished playing.


All in all, to have 2 channels instead of 1 is very useful for games :).

On my game, I wanted to be able to control more precisely which sound effects are allowed to "cut" through each other or not. So I'm using a combination of both techniques : the channel 8 is used with SpcEffect to play Sound Effect from memory that I don't want to be interrupted (explosions, etc.), while all the others less important sounds are played through the streaming method. Using both streaming and non-streaming functions at the same time works well so far!

So thanks again a lot for your SNESmod wisdom and guidance - once again, I couldn't have figured out this issue without your help.

I'll keep working on my game, and I'll post it here whenever I have a good enough build! (I still have loads of work to do on it!)