What's the most common way to implement vibrato?
Moderator: Moderators
What's the most common way to implement vibrato?
What's the most common way to implement vibrato for an nes music engine? Specifically for the pulse channels.
I'm using Famitracker.
I tried using APU Sweep, but cant get it quiet right.
Thank you.
I'm using Famitracker.
I tried using APU Sweep, but cant get it quiet right.
Thank you.
...
Re: What's the most common way to implement vibrato?
In general, vibrato is a sine function added to the note's period, looping maybe every 12 frames.
Are you looking to implement any sort of vibrato, or are you trying to exactly emulate FamiTracker's formulas for vibrato rate and depth? The latter might be more expensive in CPU time and/or ROM space.
Are you looking to implement any sort of vibrato, or are you trying to exactly emulate FamiTracker's formulas for vibrato rate and depth? The latter might be more expensive in CPU time and/or ROM space.
Re: What's the most common way to implement vibrato?
You're going to want the music engine itself to drive the pitch registers manually to do vibrato. I've seen two different methods:
A) Have a table of pitch offsets that you add to the pitch each frame; the pitch offsets will usually look like a triangle wave (e.g., 0, +1, +2, +3, +2, +1, 0 -1, -2, -3, -2, -1, loop) but I've seen other waveforms. Hirokazu Tanaka's engine and Capcom's engine do something like this.
B) Choose two pitch offsets and switch back and forth between them; this looks like a square wave and is what Konami, Natsume, and Akita Nakatsuka's engine (Zelda II) does.
Avoid writing to the 4th register of the channel (i.e., the most significant bits of the pitch) until those bits absolutely change, otherwise, you'll get crackling or buzzing artifacts since writing to that register resets the phase of the channel's waveform each time you write to it. You can freely write to the 3rd register all you want though.
A) Have a table of pitch offsets that you add to the pitch each frame; the pitch offsets will usually look like a triangle wave (e.g., 0, +1, +2, +3, +2, +1, 0 -1, -2, -3, -2, -1, loop) but I've seen other waveforms. Hirokazu Tanaka's engine and Capcom's engine do something like this.
B) Choose two pitch offsets and switch back and forth between them; this looks like a square wave and is what Konami, Natsume, and Akita Nakatsuka's engine (Zelda II) does.
Avoid writing to the 4th register of the channel (i.e., the most significant bits of the pitch) until those bits absolutely change, otherwise, you'll get crackling or buzzing artifacts since writing to that register resets the phase of the channel's waveform each time you write to it. You can freely write to the 3rd register all you want though.
- rainwarrior
- Posts: 8731
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: What's the most common way to implement vibrato?
At the engine level, Famitracker makes use of the sweep as part of its vibrato, but in an obtuse way (a way to adjust the high byte of period without a pop). It's meant to be hidden from the user though. (Edit: or maybe it doesn't... I don't see it happening in 0.4.6. There are engines that do this though.)
Famitracker does have a vibratio effect you can just enter in the effect column. If you're using Famitracker but a different engine, it's kind of up to what that engine can do. Some support the vibrato effect but many don't.
In Lizard (FTMs) I just used pitch envelopes to accomplish vibrato, rather than a dedicated effect. Generally this is a symmetrical envelope, looped where it crosses a 0 offset. The important part is that it should be symmetrical (i.e. have the same amount of positive and negative contribution). Talking about a sine wave is maybe a red herring since we have so little precision to work with. Anything symmetrical and smooth-ish should be okay.
Examples:
Code: Select all
light vibrato (5 frames long)
| -1 0 0 0 1 1 0 0 0 -1
0 0 0 -1 -1 | 1 1 1 1 0 -1 -1 -1 -1 0
wider vibrato
note: the loop point starts at -3, and the loop goes up and down by 6, so it remains centred
-1 -1 -1 | 1 1 2 1 1 -1 -1 -2 -1 -1
medium vibrato (range of 4)
0 0 0 -1 -1 | 1 1 1 1 0 -1 -1 -1 -1 0
faster vibrato (4 frames long)
0 -1 -1 -1 | 1 2 2 1 -1 -2 -2 -1
In these examples I do mostly try to approximate a sine by moving the pitch fastest as it crosses 0, but it's not really necessary to be sine-like. (That medium vibrato maybe should have had the 0s in the middle like 1 1 0 1 1 -1 -1 0 -1 -1, but it doesn't really matter.)
Also, like Drag said, if you're using an engine that does not do Famtracker's sweep trick to manipulate the high bits of period, you'll get pops if you put a wide vibrato next to a high-bit crossing. A-3 in particular, since it's so close to 256.
Re: What's the most common way to implement vibrato?
This is what I am trying to do: Get it as close as possible to Famitrackers values.
Thank you all for the great answer. Is good to have options.
...
Re: What's the most common way to implement vibrato?
...
Last edited by olddb on Wed May 05, 2021 9:47 pm, edited 1 time in total.
...
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: What's the most common way to implement vibrato?
I had been trying to do the same, e.g. recreate fx code 4 74 using Famitracker's pitch and arpeggio envelopes. I tried blind guessing and listening to figure it out but I was hoping there would be a chart somewhere
- rainwarrior
- Posts: 8731
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: What's the most common way to implement vibrato?
The 16 rows are the 16 depth settings. The 16 columns are the phase of the effect when it's used.FT 0.4.6 driver.s line 650 wrote:Code: Select all
; Vibrato table (256 bytes) ft_vibrato_table: .byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01 .byte $00, $00, $00, $00, $01, $01, $01, $01, $02, $02, $02, $02, $02, $02, $02, $02 .byte $00, $00, $00, $01, $01, $01, $02, $02, $02, $03, $03, $03, $03, $03, $03, $03 .byte $00, $00, $00, $01, $01, $02, $02, $03, $03, $03, $04, $04, $04, $04, $04, $04 .byte $00, $00, $01, $02, $02, $03, $03, $04, $04, $05, $05, $06, $06, $06, $06, $06 .byte $00, $00, $01, $02, $03, $04, $05, $06, $07, $07, $08, $08, $09, $09, $09, $09 .byte $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $09, $0A, $0B, $0B, $0B, $0B .byte $00, $01, $02, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0C, $0D, $0D, $0D .byte $00, $01, $03, $04, $06, $08, $09, $0A, $0C, $0D, $0E, $0E, $0F, $10, $10, $10 .byte $00, $02, $04, $06, $08, $0A, $0C, $0D, $0F, $11, $12, $13, $14, $15, $15, $15 .byte $00, $02, $05, $08, $0B, $0E, $10, $13, $15, $17, $18, $1A, $1B, $1C, $1D, $1D .byte $00, $04, $08, $0C, $10, $14, $18, $1B, $1F, $22, $24, $26, $28, $2A, $2B, $2B .byte $00, $06, $0C, $12, $18, $1E, $23, $28, $2D, $31, $35, $38, $3B, $3D, $3E, $3F .byte $00, $09, $12, $1B, $24, $2D, $35, $3C, $43, $4A, $4F, $54, $58, $5B, $5E, $5F .byte $00, $0C, $18, $25, $30, $3C, $47, $51, $5A, $62, $6A, $70, $76, $7A, $7D, $7F
i.e. vibrato $37 uses row $3 (depth) and adds $7 (speed) to the accumulator each frame.
Bits 0-3 of the accumulator select a column, but bits 4-5 of the accumulator reflect the direction or depth, i.e. $0X reads the row in increasing order, $1X reads it backwards, $2X is increasing but inverted result, $3X is backwards order but inverted.
So the maximum length of a vibrato's period (i.e. value $X1) is 64 frames in total. Higher speeds skip over steps (e.g. $X4 is 16 frames in total).
The code is in effect.s line 523 if you want to review it.
Last edited by rainwarrior on Wed May 05, 2021 4:28 pm, edited 2 times in total.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: What's the most common way to implement vibrato?
I'll admit that kind of went over my head.rainwarrior wrote: ↑Wed May 05, 2021 12:39 pmThe 16 rows are the 16 depth settings. The 16 columns are the phase of the effect when it's used.FT 0.4.6 driver.s line 650 wrote:Code: Select all
; Vibrato table (256 bytes) ft_vibrato_table: .byte $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01 .byte $00, $00, $00, $00, $01, $01, $01, $01, $02, $02, $02, $02, $02, $02, $02, $02 .byte $00, $00, $00, $01, $01, $01, $02, $02, $02, $03, $03, $03, $03, $03, $03, $03 .byte $00, $00, $00, $01, $01, $02, $02, $03, $03, $03, $04, $04, $04, $04, $04, $04 .byte $00, $00, $01, $02, $02, $03, $03, $04, $04, $05, $05, $06, $06, $06, $06, $06 .byte $00, $00, $01, $02, $03, $04, $05, $06, $07, $07, $08, $08, $09, $09, $09, $09 .byte $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $09, $0A, $0B, $0B, $0B, $0B .byte $00, $01, $02, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0C, $0D, $0D, $0D .byte $00, $01, $03, $04, $06, $08, $09, $0A, $0C, $0D, $0E, $0E, $0F, $10, $10, $10 .byte $00, $02, $04, $06, $08, $0A, $0C, $0D, $0F, $11, $12, $13, $14, $15, $15, $15 .byte $00, $02, $05, $08, $0B, $0E, $10, $13, $15, $17, $18, $1A, $1B, $1C, $1D, $1D .byte $00, $04, $08, $0C, $10, $14, $18, $1B, $1F, $22, $24, $26, $28, $2A, $2B, $2B .byte $00, $06, $0C, $12, $18, $1E, $23, $28, $2D, $31, $35, $38, $3B, $3D, $3E, $3F .byte $00, $09, $12, $1B, $24, $2D, $35, $3C, $43, $4A, $4F, $54, $58, $5B, $5E, $5F .byte $00, $0C, $18, $25, $30, $3C, $47, $51, $5A, $62, $6A, $70, $76, $7A, $7D, $7F
i.e. vibrato $37 uses row $3 (depth) and adds $7 (speed) to the accumulator each frame.
Bits 0-3 of the accumulator select a column, but bits 4-5 of the accumulator reflect the direction or depth, i.e. $0X reads the row in increasing order, $1X reads it backwards, $2X is increasing but inverted result, $3X is backwards order but inverted.
So the maximum length of a vibrato's period (i.e. value $X1) is 64 frames in total. Higher speeds skip over steps (e.g. $X4 is 16 frames in total).
The code is in effect.s line 523 if you want to review it.
- rainwarrior
- Posts: 8731
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: What's the most common way to implement vibrato?
Pick a depth. Go down that many rows in the table.
Pick a speed, go through the row left to right at that speed. Those are your pitch offsets. If you're using vibrato speed 1, step 1 column at a time. If using speed 2, step 2 columns, etc...
After going left to right, go right to left, then do the same but upside down, like this:
Code: Select all
0X 1X 2X 3X (accumulator)
| /\ | | |
|/ |\ | | |
/ | \| | |
| | \ | /|
| | |\ |/ |
| | | \/ |
Last edited by rainwarrior on Wed May 05, 2021 4:27 pm, edited 3 times in total.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: What's the most common way to implement vibrato?
So famitracker fx code 4 74 equals "Start at row 7, then increment by 4?"rainwarrior wrote: ↑Wed May 05, 2021 1:46 pmPick a depth. Go down that many rows in the table.
Pick a speed, go through the row left to right at that speed. Those are your pitch offsets. If you're using vibrato speed 1, step 1 column at a time. If using speed 2, step 2 columns, etc...
After going left to right, go right to left, then do the same but upside down, like this:I believe the rows of the table are equivalent to the first 1/4 of a sine wave, scaled and rounded to various sizes, but I haven't checked.Code: Select all
0X 1X 2X 3X (accumulator) | /\ | | | |/ |\ | | | / | \| | | | | \ | /| | | |\ |/ | | | | \/ |
- rainwarrior
- Posts: 8731
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: What's the most common way to implement vibrato?
I didn't know that Famitracker had an actual NES-compatible driver. Would this code work if I copied and pasted it into a .asm file and assembled it as an NES rom?
Re: What's the most common way to implement vibrato?
The FamiTracker driver is fairly large in ROM and RAM size. You'd also need to add some layer on top to make sound effects.
There are other drivers that are smaller and better suited to games in general, such as Pently, FamiTone2, FamiTone4, and GGSound. All have available tools to convert the text export from FamiTracker, though all have limits to some extent on what effects and envelope features will and won't survive translation.
There are other drivers that are smaller and better suited to games in general, such as Pently, FamiTone2, FamiTone4, and GGSound. All have available tools to convert the text export from FamiTracker, though all have limits to some extent on what effects and envelope features will and won't survive translation.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: What's the most common way to implement vibrato?
I've only ever heard of GGsound, it's fairly easy to use but doesn't work with the effects table or expansion audio, both of which I really want to have in my game's musictepples wrote: ↑Wed May 05, 2021 5:53 pm The FamiTracker driver is fairly large in ROM and RAM size. You'd also need to add some layer on top to make sound effects.
There are other drivers that are smaller and better suited to games in general, such as Pently, FamiTone2, FamiTone4, and GGSound. All have available tools to convert the text export from FamiTracker, though all have limits to some extent on what effects and envelope features will and won't survive translation.