The Definitive Guide to Composing NESmaker-Compatible Music and Sound

jorotroid

Member
Andrew. Pierce.2032 said:
A couple of things I discovered that I didn't see mentioned:

Frames in the FamiTracker module have to progress together. If you want to loop a channel, you have to loop ALL the channels.

so your module can look like this:

00|00 00 00 00 00
01|01 01 01 01 01
02|01 01 01 01 01
03|02 02 02 02 02


But it can't look like this:

00|00 00 00 00 00
01|01 01 01 01 01
02|02 02 02 01 02
03|03 03 03 01 03

I've seen other people at times say that, but it's not true. Here are the frames from my medieval theme in the 4.5 Tutorial Sound Pack as an example.

00 : 00 00 03 00 00
01 : 00 00 01 01 00
02 : 00 04 00 02 00
03 : 00 04 01 01 00
04 : 05 01 01 02 00
05 : 02 02 00 04 00
06 : 03 03 02 03 00
07 : 06 05 05 01 00
08 : 07 06 06 01 00
09 : 01 01 02 02 00
0A : 01 01 02 02 00
0B : 08 07 04 05 00

If you're having an issue there must be another cause. What exactly is the issue you get?


Andrew. Pierce.2032 said:
Another problem I ran into is that NesMaker does not like empty frames. I had a song that used some polyrhthmic envelopes to make some ambient textures across a couple frames and it would it kept spitting back the error message "Object reference not set to an instance of an object" (Same error for the issue above. My guess is that famitracker tries to consolidate the blank and irregular frames in a way that either Nesmaker or the GG sound engine doesn't support.) As long as you have a note on at least one channel per a frame it shouldn't be a problem. I also learned that instrument trails don't carry between frames in the compiled rom the way they do in famitracker so I'll be needing to fill those frames in regardless.

Also another thing I have not experienced. Like pattern 00 of frame 00 of the noise channel in my example above is completely blank. But maybe that is because it's at the beginning? Maybe the issue is from a blank pattern in certain contexts?
 

jorotroid

Member
CutterCross said:
- Looping with the Bxx (must be present in all channels, using unique patterns) command **

** Bxx effect is NOT supported by default, and can only be re-implemented by using GGsound's official ft_txt_to_asm Python script or the GGsound ft_txt_to_asm executable on this forum.

So a couple of things about Bxx. The reason why you "need" to put it on every channel is that otherwise the loop will only apply to the channel that it is on. That might actually be useful in some cases, but also Bxx might not always be the right way of doing loops anyway. Again using my medieval track as an example, I used the Bxx command on it, so its suppose to have a later restart point and I can compare what it looks like with the NESmaker converter vs the ggsound converter. (I was sort of gambling that Bxx would be fixed for NESmaker 4.5's version of the converter, but that is sort of besides the point)

If you open up the AllSongs_WithSFX.asm file in the GameEngineData\Sound folder after importing the txt and exporting the rom, this is what the data for the frames of the first square channel would look like. I'll add some comments to make it what is going on clearer.

Code:
MedievalTimes_square1:
	.db CAL,<(MedievalTimes_square1_0),>(MedievalTimes_square1_0)	; Each line is a frame for this channel.
	.db CAL,<(MedievalTimes_square1_0),>(MedievalTimes_square1_0)	; CAL is a ggsound opcode telling the engine to 
	.db CAL,<(MedievalTimes_square1_0),>(MedievalTimes_square1_0)	; "call" the address defined by the next 2 bytes.
	.db CAL,<(MedievalTimes_square1_0),>(MedievalTimes_square1_0)	; The 2 bytes are the lo and hi bytes for the
	.db CAL,<(MedievalTimes_square1_5),>(MedievalTimes_square1_5)	; address of the start of the pattern. You can 
	.db CAL,<(MedievalTimes_square1_2),>(MedievalTimes_square1_2)	; the pattern number and the end of the label
	.db CAL,<(MedievalTimes_square1_3),>(MedievalTimes_square1_3)	; for these bytes.
	.db CAL,<(MedievalTimes_square1_6),>(MedievalTimes_square1_6)
	.db CAL,<(MedievalTimes_square1_7),>(MedievalTimes_square1_7)
	.db CAL,<(MedievalTimes_square1_1),>(MedievalTimes_square1_1)
	.db CAL,<(MedievalTimes_square1_1),>(MedievalTimes_square1_1)
	.db CAL,<(MedievalTimes_square1_8),>(MedievalTimes_square1_8)
	.db GOT								; GOT is the ggsound opcode for "goto"
	.dw MedievalTimes_square1					; Note that this is the same label as the one at the top.

And here is what that part would look like in the asm file generated by the ggsound converter:

Code:
_MedievalTimes_square1:
  .db CAL,<(_MedievalTimes_square1_0),>(_MedievalTimes_square1_0)
  .db CAL,<(_MedievalTimes_square1_0),>(_MedievalTimes_square1_0)
 _MedievalTimes_square1_loop:						; Note this label that wasn't in the NESmaker output.
  .db CAL,<(_MedievalTimes_square1_0),>(_MedievalTimes_square1_0)
  .db CAL,<(_MedievalTimes_square1_0),>(_MedievalTimes_square1_0)
  .db CAL,<(_MedievalTimes_square1_5),>(_MedievalTimes_square1_5)
  .db CAL,<(_MedievalTimes_square1_2),>(_MedievalTimes_square1_2)
  .db CAL,<(_MedievalTimes_square1_3),>(_MedievalTimes_square1_3)
  .db CAL,<(_MedievalTimes_square1_6),>(_MedievalTimes_square1_6)
  .db CAL,<(_MedievalTimes_square1_7),>(_MedievalTimes_square1_7)
  .db CAL,<(_MedievalTimes_square1_1),>(_MedievalTimes_square1_1)
  .db CAL,<(_MedievalTimes_square1_1),>(_MedievalTimes_square1_1)
  .db CAL,<(_MedievalTimes_square1_8),>(_MedievalTimes_square1_8)
  .db GOT
  .dw _MedievalTimes_square1_loop					; Note that this is the new label, not the start label

You can see in the NESmaker outputted file at the end of the frame sequence it defines a word that this is the address of the label for the start of the sequence of frames, MedievalTimes_square1. But in the ggsound outputted file, it has a different label defining the word at the end with "_loop" added to the end of the label, and the location of the label precedes the frame the song should be looping back to. This is how the ggsound engine handles looping. One nice thing about the way they designed it is that this means looping to a later point doesn't take any additional space than looping back to the beginning. Using Bxx can be fine in some situations, but what if you want the last frame of one or more of the tracks of your song to be a copy of another frame? You would have to make a copy of that frame and put the Bxx command at the end and having a copy of a frame would mean that you'll have a whole frame of redundant data that will get exported.

So to summarize, if the end of your song in completely unique, Bxx is fine to use. If the last frame reuses any frames, it's better to edit the outputted asm file from the ggsound converter after the fact. Just be sure to make the changes to all of the channels.

Additionally, I haven't done this yet but I think you could also use the Bxx command to make pickup notes or a shortened intro frame because Bxx does tell the ggsound converter to stop reading the frame of that channel after that point. You would probably also have to edit the file to make it work.

Also you can't edit the AllSongs_WithSFX.asm file because it gets overwritten by NESmaker on export. If anyone doesn't feel like downloading the ggsound converter, I suppose you could make a copy of the AllSongs_WithSFX.asm after an export, do some edits to the copy, and then import the copy.



Ok, one more thing while I'm here. Not sure if this has been mentioned before, but if you do use the ggsound converter, don't use the note release command (pressing the '\' key in the pattern editor that results in a big equal sign). This will give you an error when you go to export your rom. Using the NESmaker converter this will result in the same output as a note cut (pressing the '1' key giving you a big dash in your pattern). You probably should just always use note cuts anyway especially considering ggsound doesn't support the function of the note releases anyway.
 
jorotroid said:
Andrew. Pierce.2032 said:
A couple of things I discovered that I didn't see mentioned:

Frames in the FamiTracker module have to progress together. If you want to loop a channel, you have to loop ALL the channels.

so your module can look like this:

00|00 00 00 00 00
01|01 01 01 01 01
02|01 01 01 01 01
03|02 02 02 02 02


But it can't look like this:

00|00 00 00 00 00
01|01 01 01 01 01
02|02 02 02 01 02
03|03 03 03 01 03

I've seen other people at times say that, but it's not true. Here are the frames from my medieval theme in the 4.5 Tutorial Sound Pack as an example.

00 : 00 00 03 00 00
01 : 00 00 01 01 00
02 : 00 04 00 02 00
03 : 00 04 01 01 00
04 : 05 01 01 02 00
05 : 02 02 00 04 00
06 : 03 03 02 03 00
07 : 06 05 05 01 00
08 : 07 06 06 01 00
09 : 01 01 02 02 00
0A : 01 01 02 02 00
0B : 08 07 04 05 00

If you're having an issue there must be another cause. What exactly is the issue you get?


Andrew. Pierce.2032 said:
Another problem I ran into is that NesMaker does not like empty frames. I had a song that used some polyrhthmic envelopes to make some ambient textures across a couple frames and it would it kept spitting back the error message "Object reference not set to an instance of an object" (Same error for the issue above. My guess is that famitracker tries to consolidate the blank and irregular frames in a way that either Nesmaker or the GG sound engine doesn't support.) As long as you have a note on at least one channel per a frame it shouldn't be a problem. I also learned that instrument trails don't carry between frames in the compiled rom the way they do in famitracker so I'll be needing to fill those frames in regardless.

Also another thing I have not experienced. Like pattern 00 of frame 00 of the noise channel in my example above is completely blank. But maybe that is because it's at the beginning? Maybe the issue is from a blank pattern in certain contexts?


I can't imagine what else it could be but I'm also not sure why yours would work and mine wouldn't. I loaded all of my instruments into an otherwise blank song and everything worked fine. If I make a song like this:

00|00 00 00 00 00
01|01 01 01 00 00

with a C5 at the start of every pattern, then when importing the famitracker txt to nesmaker I'll get the error message mentioned above of "Object reference not set to an instance of an object". Changing the 00 patterns in frame 01 to 01 patterns :
(01| 01 01 01 01 01) allows it to import fine. Likewise, if I take that same now-functioning song and I leave all the 01 patterns for each channel in frame 01 completely blank I'll get the same error message when trying to import the txt to nesmaker. Adding a single note on any channel in the otherwise blank frame fixes the issue.

If you have a solution I would genuinely love to hear it. It would be great to take back all of space used up by copy/pasted patterns.
 

jorotroid

Member
Andrew. Pierce.2032 said:
If you have a solution I would genuinely love to hear it. It would be great to take back all of space used up by copy/pasted patterns.

I'll try doing what you said you did after I get off work, but also if you would be willing to share your txt file, I could take a look and see if I can pinpoint the problem.
 
jorotroid said:
Andrew. Pierce.2032 said:
If you have a solution I would genuinely love to hear it. It would be great to take back all of space used up by copy/pasted patterns.

I'll try doing what you said you did after I get off work, but also if you would be willing to share your txt file, I could take a look and see if I can pinpoint the problem.

I've already reformatted my song layout to comply with what nesmaker would accept but I'll make a reverted version as well and dm them to you.

EDIT: After taking the time to go back and remove all of the duplicate patterns the txt file imported into nesmaker without a hitch. I don't know what I've done differently but I'll take it.
 

jorotroid

Member
Andrew. Pierce.2032 said:
EDIT: After taking the time to go back and remove all of the duplicate patterns the txt file imported into nesmaker without a hitch. I don't know what I've done differently but I'll take it.

Awesome!

I've been doing some tests on the blank frames error. I think what causes it is if all patterns with the same index are blank and at least one of those patterns is used. So if pattern 01 of your squares, triangle, and noise channels are all blank, but for whatever reason you didn't end up using any pattern 01 in your song at all, you would be fine. But if you use any pattern 01 with all of them being blank, you will get the error. If you put something in one of those patterns, it will work again. Surprisingly,
even if the one pattern that isn't blank is not actually used in the song, this will still allow you to import error free; but you probably don't want to do that because that unused pattern would just be a waste of space.

I think what is going on under the hood is that there is some kind of optimization in the converter to see when all patterns of an index are all blank and if so, skip creating data for that pattern. But this optimization neglects to check if any of the patterns are actually getting used. Then when NESmaker goes to import the audio after converting it, it see that there is a reference to a pattern in the pattern sequence, but there is no data for that pattern.

I can't help but to feel that there are more permutations that could lead to this error manifesting, but I'm not sure what other configurations to try next at this point.

Also somewhat related that might be good to know is what exactly does happen when you export a successful blank frame. One thing the exporters do is automatically generate one extra instrument called "silent." This instrument has a volume of 0 and gets played for note cuts, but also gets played at the beginning of any frame that doesn't already have another note designated for the beginning. This means that note do not sustain past the end of a frame like they do in NESmaker. So if you wanted to used a blank frame with a note sustaining over it that started from the previous frame, that won't be possible.
 

PasseGaming

Active member
Oh good, I was looking for this thread. Lost it when the site updated awhile back. Not that I plan on doing many songs (I have literally zero musical talent), this is still useful for sound effects and perhaps a basic tune or two if need be.
 

puppydrum64

Active member
I was trying to create a song that was entirely done with the noise channel so that I can have a looping sound for when the boss is defeated. However, the sound in-game comes from the pulse channel instead! I don't know why.
 

Jonny

Well-known member
Use Shiru's NES Space Checker. It's one of the quintessential NESdev tools you should always have at the ready. Bank $1B is the music bank in NESmaker's default engine.

Regarding ROM space.. Has anyone successfully switched to other banks, say if they have a lot of music? I see there is a SwitchBank #$1B in NMI and Initialization scripts. So, would it be feasible to add some sort of check to (for example) use one bank for underworld music and one for overworld music.

EDIT: I just read this http://www.nesmakers.com/index.php?threads/whats-this-all-about.1396/ which answered my questions so I'm all good :)
 
Last edited:
INTRODUCTION:



Okay, this is going to be a big one.

I've seen a ton of information about NESmaker's sound capabilities scattershot all over the forum. Some of it is outdated/incorrect, and I wanted to make this topic to be a sort of definitive list of limitations/quirks and rules to follow creating music and SFX with NESmaker. I have learned a lot composing all sorts of music/SFX for this software and optimizing the music for Mystic Searches. Keep in mind that this list is for NESmaker 4.1.5 (and 4.5.6.), so older versions may not have exactly the same limitations as this list. So with all that out of the way, let's get started.

For more information regarding Music and SFX for NESmaker projects, watch the official "Zero to 8-Bit Hero" tutorial on Music and SFX by The New 8-Bit Heroes:

View: https://www.youtube.com/watch?v=Qt3Gd9pTcbE


NESmaker uses a modified version of the Gradual Games Sound Engine, AKA GGsound. The following list of features come from GGsound's official webpage.



GGSOUND'S FEATURES (STRAIGHT FROM THE OFFICIAL GGSOUND WEBPAGE):



- Square [Pulse] 1, 2, Triangle, Noise, and DPCM channels *
- Volume, Arpeggio, Pitch and Duty envelopes
- Hi-Pitch envelopes are NOT supported
- Looping envelopes at an arbitrary loop point
- Speed and Tempo
- Looping with the Bxx (must be present in all channels, using unique patterns) command **
- Note cuts
- Tempo and pitch adjustment for NTSC, PAL and Dendy
- Multi-song export
- Sound effects on two channels
- Pause/unpause
- All 87 audible notes in FamiTracker
- 128 of each type of envelope ***
- 128 songs ***
- 128 sound effects ***
- 256 byte long envelopes ***

Source: http://www.gradualgames.com/p/sound-engine.html

It's important to note that GGsound does NOT support note effects (aside from Bxx) or the channel volume column in FamiTracker. Anything written there will be ignored in the compiled ROM.
Also keep in mind that Releasing envelopes at an arbitrary loop point is NOT supported.

ALSO NOTE: This should be obvious, but GGsound does NOT support famicom expansion audio of any kind. The North American and PAL region NES (unmodified) systems cannot take advantage of expansion audio in the first place, and VERY few famicom games even took advantage of expansion audio (aside from FDS).



NESMAKER-SPECIFIC QUIRKS/LIMITATIONS:



* DPCM channel is NOT supported by default, and can only be re-implemented by following this topic:
** Bxx effect is NOT supported by default, and can only be re-implemented by using GGsound's official ft_txt_to_asm Python script or the GGsound ft_txt_to_asm executable on this forum. The latter of which can be found here:
*** Limited to 64 instruments by default, as well as 64 songs and SFX entries combined.
*** The amount of songs/SFX you will be able to use will also be limited by the ROM space you have to work with, and how complex/long your songs and SFX are.



BEST PRACTICES FOR COMPOSING MUSIC/SFX:



- It's been reported by The New 8-Bit Heroes that putting a Pulse channel SFX only on Pulse Channel 1 can cause some issues with playback. It's recommended that any single-channel Pulse SFX be located on Pulse channel 2.
- It's recommended to keep the Tempo setting at 150 BPM, while instead using the Speed setting to change how fast/slow the song plays.
- While note cuts are supported, it's also a good idea to create a "silent" instrument (an instrument with a volume envelope of 0) to act as a note cut, in case any issues arise with using regular note cuts.
- For SFX, it is a good idea to add a "silent" instrument note before the note cut to make sure the SFX ends properly.
- Do NOT delete instruments in the middle of your instrument bank without replacing them! If there is a gap in the instrument numbers such as this: (00, 01, 02, 04,) NESmaker will go haywire and will prevent the file from importing.
- Make sure your frames for each channel in the frame editor go in order. (For one channel, something like this: 00, 01, 02, 03... will work. Or if you're repeating frames, something like this: 00, 00, 01, 01... will also work. Do NOT do something like 00, 02, 01, 03...)
- For adding pitch bends by looping the Pitch envelope, there is NO lower/upper bounds handling like there is in FamiTracker! Once the lowest pitch is reached it will loop back to the highest pitch. Likewise, once the highest pitch is reached it will loop back to the lowest pitch. Keep this in mind when using large pitch bends.
- Avoid using notes lower than A-0 on the Pulse and Triangle channels. In FamiTracker, the lowest audible note on those channels is A-0, and all notes below A-0 sound identical to each other. However, these lower notes do not behave the same way in GGsound. Using those notes will cause their pitch to behave incorrectly.
- Blank note patterns following other distinct note patterns will prevent your music file from importing into NESmaker.
- Sustained notes do not carry over frames when played through GGsound. You'll have to design your music around this.
- On the Triangle channel, using a silent instrument (volume envelope of 0) with a pitch significantly higher than the last played pitch will cause an audible click during playback. This may be something you want to avoid or embrace in your sound design.



BEST PRACTICES FOR SAVING ROM SPACE:



- Putting more notes in your song will take up more ROM space, but keep in mind that blank spaces do NOT count towards ROM space!
- It's best to create instruments with longer envelopes (putting fewer notes down as a result) than it is to create instruments with simpler envelopes (putting more notes down as a result). More notes take up more ROM space than longer envelopes.
- More instruments DO take up more ROM space, but the amount is trivial compared to the amount of space taken up by more note data.
- Repeat frames as much as you can. The small amount of ROM space it takes to repeat another frame is trivial compared to the massive amount of ROM space taken by creating a new frame with new notes.
- Cram your notes together if you can, and run the song at a slower speed to keep the same tempo. This can save the tiny amount of ROM space taken up by adding/repeating a frame, but it's rare that you'll have to resort to this method to free up space.



OTHER THINGS OF NOTE (AS OF NESMAKER 4.5.9):



- The 09 ORDER limitation that NESmaker had in the past has appeared to be gone. You can write songs longer than 10 frames now.
- Noise channel arpeggios don't seem to be inverted anymore.
- NESmaker can be fickle with filenames and song names when trying to import. Make sure that your filenames and song names only use letters (combinations of uppercase or lowercase is fine) and numbers, and don't use spaces or weird characters.
- Instrument names can have spaces, but they cannot START with a number. They should otherwise adhere to the previous naming rules.
- For naming SFX, make sure to label them as "sfx_" followed by the SFX name. The "sfx_" part of the name must be lowercase. Use the same naming rules as previously stated.
- Older versions of NESmaker can have some different quirks/limitations than what's been shown here.



If any of this information is incorrect/outdated, or if there is anything additional you've found regarding NESmaker's music quirks/limitations, please let me know.
Amazing topic! You are very good! I'm not able to add a song to nesmaker, it keeps getting an error. Could you help me with this? If you want, I'll send you the file...?The error occurs when adding track to the sound engine module
 

Shaoran

New member
Hello everyone

I have a problem with my music and it stops a channel when I run an FX.

Should I create the music by reserving a channel just for the FX?
 

Logana

Well-known member
Hello everyone

I have a problem with my music and it stops a channel when I run an FX.

Should I create the music by reserving a channel just for the FX?
Have you made sure to end the sfx with a blank instrument? it will reduce the channel stopping
 

GlassFrog

Member
Hello everyone

I have a problem with my music and it stops a channel when I run an FX.

Should I create the music by reserving a channel just for the FX?
Hi @Shaoran did you ever fix this problem as I'm an experiencing it also.
 
Top Bottom