FamiTone2 audio library

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
FamiTone2 audio library
by on (#123756)
Download FamiTone2

The original FamiTone got a major update, with data formats change and player and tools code rewrite. The most important improvements are:

- Built-in FamiTracker text export support instead of the old TextExporter plug-in
- Faster code
- Smaller data size
- Tempo support
- Full NTSC/PAL support, with pitch and speed compensation
Re: FamiTone2 audio library
by on (#123758)
Dendy support too?
Re: FamiTone2 audio library
by on (#123759)
No.
Re: FamiTone2 audio library
by on (#123767)
Which assemblers are supported, which expansion audio is supported, and can any other formats be imported (such as MML or Csound)?
Re: FamiTone2 audio library
by on (#123772)
zzo38 wrote:
Which assemblers are supported

From readme.txt:
Quote:
text2data outputs data in NESASM format by default, you can use -ca65 or -asm6 switches to get output for these assemblers.

From text2data.cpp:
Code:
#define OUT_NESASM   0
#define OUT_CA65   1
#define OUT_ASM6   2


Quote:
which expansion audio is supported

Doesn't look like any. From text2data.cpp:
Code:
#define MAX_PACKED_PATTERNS   (5*MAX_ORDER*MAX_SUB_SONGS)

That covers pulse, pulse, triangle, noise, and DPCM.

From nsf2data.cpp:
Code:
   if(nsf_data[0x7b])
   {
      printf("Expansion chips are not supported\n");
      free(nsf_data);
      return 1;
   }

Let me know which expansion audio is supported by any all-new-parts flash cartridge.

Quote:
and can any other formats be imported (such as MML or Csound)?

I see something that appears designed for sound effects in FamiTracker NSFs, but not much more.
Re: FamiTone2 audio library
by on (#123776)
Is it really necessary to quote random code pieces and make guesses when everything is clearly stated in the readme.txt, and is not changed since the original version? Please understand, I don't need any docs by myself, I spend quite some time and effort to write them for your convenience. Please read them.

line 14 of the readme.txt wrote:
Expansion sound chips are not supported.

'How to use the library' section wrote:
The main version of the FamiTone2 is written in NESASM. There are
versions for CA65 and ASM6 assemblers included in the package as well.


zzo38 wrote:
can any other formats be imported (such as MML or Csound)

No. It is clearly explained in the readme.txt which formats are supported and how it all works. It is possible to use other import sources, but you'll have to write your own converter, which is a good half of the whole thing.
Re: FamiTone2 audio library
by on (#123819)
I'm having trouble getting this to work with cc65. I have sound effects working fine, but I can't get music to work at all.

This line of code is what *SHOULD* play the music:
Code:
if(controllerInput&PAD_START) music_play(music_test);


Here is the function definition for music_play (I DID modify it slightly):
Code:
_music_play:
   stx <PTR
   tax
   ldy <PTR
   jmp FamiToneMusicPlay


Is there something I'm missing?
Re: FamiTone2 audio library
by on (#123826)
If music_play is a fastcall function with one parameter, that parameter is in A. What are you doing with X?
Re: FamiTone2 audio library
by on (#123832)
The confusion maybe stems from the fact that in FamiTone1, FamiToneMusicStart took a 16-bit parameter (pointer to the music data), whereas in FamiTone2 FamiToneMusicPlay takes a single byte (sub song number).
Re: FamiTone2 audio library
by on (#123843)
What exactly do I need to do in order to get a song to play with cc65?
Re: FamiTone2 audio library
by on (#123844)
Your _music_play function is broken, is what I was saying. I don't know where you got that from, as it does not appear to be part of FamiTone2.

The first question is whether it is declared correctly. If it takes one parameter in A, it should be declared like this:
Code:
extern void __fastcall__ music_play(unsigned char a);


The second problem is the contents of your _music_play routine. There is no useful value in X when it music_play is called from C, so storing it is counter-productive. Similarly, I don't know what you're doing with X or Y before you call FamiToneMusicPlay, which according to the readme takes a single parameter in A. Your _music_play should just look like this:
Code:
_music_play:
    jmp FamiToneMusicPlay


The rest of how to use it is in the readme, from what I can tell. Did you initialize it?
Re: FamiTone2 audio library
by on (#123860)
Yes, thanks! I really didn't have any problems with version 1 but I appreciate the work that went in the text export support and better performance.
Re: FamiTone2 audio library
by on (#125026)
With these changes, Dendy can be supported by separating out tempo and pitch. Note the different input spec of A for FamiToneInit

Code:
--- famitone2.s   2014-02-03 11:15:22.886592429 -0500
+++ famitone2-edit.s   2014-02-03 11:17:29.781515804 -0500
@@ -209,7 +209,7 @@
 
 ;------------------------------------------------------------------------------
 ; reset APU, initialize FamiTone
-; in: A   0 for PAL, not 0 for NTSC
+; in: A   bit 7 is frame rate. bit 6 is pitch. 0 for PAL, 1 for NTSC
 ;     X,Y pointer to music data
 ;------------------------------------------------------------------------------
 
@@ -221,10 +221,7 @@
    sty <FT_TEMP_PTR_H
 
    .if(FT_PITCH_FIX)
-   tax                  ;set SZ flags for A
-   beq @pal
-   lda #64
-@pal:
+   and #192            ; mask out other bits
    .else
    .if(FT_PAL_SUPPORT)
    lda #0
@@ -374,8 +371,8 @@
    bne @set_channels
 
 
-   lda FT_PAL_ADJUST      ;read tempo for PAL or NTSC
-   beq @pal
+   bit FT_PAL_ADJUST      ;read tempo for PAL or NTSC
+   bpl @pal
    iny
    iny
 @pal:
@@ -580,6 +577,7 @@
    adc FT_CH1_NOTE_OFF
    .if(FT_PITCH_FIX)
    ora FT_PAL_ADJUST
+   and #127            ;zero out bit 7
    .endif
    tax
    lda FT_CH1_PITCH_OFF
@@ -613,6 +611,7 @@
    adc FT_CH2_NOTE_OFF
    .if(FT_PITCH_FIX)
    ora FT_PAL_ADJUST
+   and #127            ;zero out bit 7
    .endif
    tax
    lda FT_CH2_PITCH_OFF
@@ -646,6 +645,7 @@
    adc FT_CH3_NOTE_OFF
    .if(FT_PITCH_FIX)
    ora FT_PAL_ADJUST
+   and #127            ;zero out bit 7
    .endif
    tax
    lda FT_CH3_PITCH_OFF
@@ -1010,8 +1010,8 @@
 
    .if(FT_PITCH_FIX)
 
-   lda FT_PAL_ADJUST      ;add 2 to the sound list pointer for PAL
-   bne @ntsc
+   bit FT_PAL_ADJUST      ;add 2 to the sound list pointer for PAL tempo
+   bmi @ntsc
    inx
    bne @no_inc1
    iny


Edit: typo
Re: FamiTone2 audio library
by on (#125045)
Tempo support makes this a huge improvement. Thank you Shiru!
Re: FamiTone2 audio library
by on (#125176)
I translated the FamiTone2 library to the assembler format used by Ophis. Because Ophis does not support conditional compilation (ifdef, etc.), I simply left all features enabled.

Total library size is 1632 bytes, including 259 bytes of data. Song data for my project is 20% smaller than the previous version of FamiTone.
Re: FamiTone2 audio library
by on (#125534)
I got famitone2 (v1.0) working after some struggling... In the process I found a bug in nesasmc which causes asm6 version of famitone2 to be broken in v1.0 (famitone2_asm6.asm)! Reason is that "HIGH" function is incorrectly converted to "<" on line 131 in nesasmc.cpp. As a fix, change "<" to ">" and reconvert famitone2.asm. (I'm not using asm6 though. I have my own assembler.)

In addition to this, I encountered cryptic error message "Pattern not found" when converting a song with text2data. Reason is, text2data assumes no gaps in patterns, i.e. if max pattern number is 1E, all patterns in range 00..1E must exist. Otherwise you get the error. I got this error because I used FamiTracker "clear unused patterns". As a workaround, I exported song as text and modified the file so that there were be no gaps in patterns (i.e. modified lines starting w/ "ORDER" and "PATTERN"). Then I imported the fixed one back to FamiTracker.

After this I got a problem with wrong instruments played by famitone2 during runtime. Reason was that text2data skipped exporting unused instruments to conserve space, and while doing so, it didn't adjust exported patterns accordingly (i.e. if instrument 1 is unused, song instruments 2,3,4 will incorrectly play instruments 3,4,5 during runtime). As a workaround, I just used the unused instruments somewhere in the song -- pretty stupid, but works :) To find unused instruments in FamiTracker, I used "clear unused instruments". Then I replaced the cleared instruments with dummy ones.

Anyways, good work Shiru! It needs bit polishing, but is really good. Have you considered using Python (or similar) instead of C for the tools? Text file parsing would be at least 10x easier with Python than C...
Re: FamiTone2 audio library
by on (#125539)
tsone wrote:
Have you considered using Python (or similar) instead of C for the tools? Text file parsing would be at least 10x easier with Python than C...

But that would make Python a dependency. Under Windows, a user has to explicitly download 15 megs of interpreter and ask the computer's administrator (head of household, school/library IT, etc.) to install it. It's not like GNU/Linux where most distributions install Python from the disc.
Re: FamiTone2 audio library
by on (#126113)
So today I was getting a infinite loop crash from FamiToneUpdate, so I traced it down to the branch always in env_read_value (line 545)

During the loop FT_TEMP_PTR was pointing to a unused part of the rom. I'm not sure how to diagnose why that happened, but as a result Y ended up being $FF before the increment and fell through to env_special which looped to env_read_value with Y still being set to $FF. I changed the branch to a jmp and the infinite loop was fixed. I then also changed the branch always in set_speed (line 890) to a jmp just in case.
Re: FamiTone2 audio library
by on (#126115)
Might I recommend making note of the existence of famitone2 in the original famitone's thread first post? The first place google led me was the thread of the old version and only realized there was a second version by chance when perusing unread posts.
Re: FamiTone2 audio library
by on (#126126)
43110 wrote:
So today I was getting a infinite loop crash from FamiToneUpdate, so I traced it down to the branch always in env_read_value (line 545)

During the loop FT_TEMP_PTR was pointing to a unused part of the rom. ...


I got exact same symptoms. First of all, don't use broken ASM6 conversion of famitone2 (v1.0 release). It corrupts the high byte of FT_TEMP_PTR, causing unexpected behavior such as INF loops. If you're not using ASM6 source, then issue is likely caused by text2data. Did you verify all instruments are used in the song (in FamiTracker)?

Why? text2data does not handle correctly songs with unused instruments. If there are unused instruments, invalid pattern data may be generated by text2data, causing famitone2 to play non-existent instruments, which in turn will lead to unexpected behavior such as INF looping. Please check my previous post.
Re: FamiTone2 audio library
by on (#126127)
I just found out that empty patterns (without notes, effects etc.) are not exported to text by FamiTracker (v0.4.2). This means text2data can give "Pattern not found" error for a valid reason (since pattern truly doesn't exist in the text).

As a workaround, one can add a do-nothing note or effect in the empty pattern (so that the pattern will be exported). Then text2data will find the pattern without error.
Re: FamiTone2 audio library
by on (#126131)
tsone wrote:
First of all, don't use broken ASM6 conversion of famitone2 (v1.0 release). It corrupts the high byte of FT_TEMP_PTR

tsone wrote:
In the process I found a bug in nesasmc which causes asm6 version of famitone2 to be broken in v1.0 (famitone2_asm6.asm)! Reason is that "HIGH" function is incorrectly converted to "<" on line 131 in nesasmc.cpp.

:oops: That was it. Fortunately there's only one place the HIGH function is used, and it's for the envelope pointer.
Code:
--- famitone2_asm6.asm   2014-02-09 23:43:08.000000000 -0500
+++ famitone2_asm6_fix.asm   2014-02-25 23:06:06.020665072 -0500
@@ -305,7 +305,7 @@
 
    lda #< (_FT2DummyEnvelope)
    sta FT_ENV_ADR_L,x
-   lda #<(_FT2DummyEnvelope)
+   lda #>(_FT2DummyEnvelope)
    sta FT_ENV_ADR_H,x
    lda #0
    sta FT_ENV_REPEAT,x
Re: FamiTone2 audio library
by on (#128627)
I'm having a problem with Famitone2. During the game (that I'm working on), the triangle channel in my song is silent. I've even tried putting the song in the demo supplied with Famitone2, and it still makes no difference, but the other song in the demo still plays fine and so does that sound effect that uses the triangle channel. Also, the pitch envelopes in the song aren't working, but like I said the pitch envelopes in the other demo song work.

I also tried including one of the demo songs into my game to see if it would work fine there, and it does. That leads me to believe that it has to be a problem with the music data (for my song), but I don't know what it is.