| | tlr
Registered: Sep 2003 Posts: 1790 |
Scaled vibrato strategies?
Do anyone of you have any good fast/compact vibrato strategies to share?
I'm aware of the basic difference from the neighbouring note technique but that is usually implemented in a slow way.
I'd like some pointers for more efficient stuff.
(Object code is fully acceptable) |
|
| | Stone
Registered: Oct 2006 Posts: 172 |
In the Prosonix player I use extended frequency tables (5 octaves below c#0). It's quite fast, but takes up more memory. The code gives about the same perceived vibrato level across the scale and looks something like this:
; x - voice
; y - instrument#
lda note,x
lsr
adc instrument_vib,y
tay
lda vib_lo,y
adc current_frq_lo,x
sta current_frq_lo,x
lda vib_hi,x
...
(The vib_lo table continues into the ordinary frq_lo table)
This code was written around 1988, so I'm sure somebody has come up with something better. I think Søren (Jeff) has done something similar though. |
| | Hein
Registered: Apr 2004 Posts: 954 |
For my musicroutine vibrato is part of the glissando/portamento subroutine.
So a vibrato table could look something like:
00 dpth 03
01 up 02
02 down 04
03 up 02
04 loop 01
Then the portamento subroutine does something like:
;x=channel ($00,$07,$0e)
;c=1 down / c=0 up
lda v1_porta_lfo_depth,x
and #$7f
beq porta_program_set_values
php
clc ;needs to be cleared, else vibo will not equalize
adc v1_note_base,x
tay
cpy #96
lda #0
bcc +
lda freq_table_hi-96,y
+
plp
bcc +
eor #$ff
+
sta zp_idx_hi
lda freq_table_hi,y
bcc +
eor #$ff
+
adc v1_freq_lo_buffer,x
sta v1_freq_lo_buffer,x
lda v1_freq_hi_buffer,x
adc zp_idx_hi
sta v1_freq_hi_buffer,x
;... Do more freq stuff like finetune ...
With frequency tables:
freq_table_hi
.byte $01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01
.byte $02,$02,$02,$02,$02,$02,$02,$03,$03,$03,$03,$03
.byte $04,$04,$04,$04,$05,$05,$05,$06,$06,$06,$07,$07
.byte $08,$08,$09,$09,$0a,$0a,$0b,$0c,$0d,$0d,$0e,$0f
.byte $10,$11,$12,$13,$14,$15,$17,$18,$1a,$1b,$1d,$1f
.byte $20,$22,$24,$27,$29,$2b,$2e,$31,$34,$37,$3a,$3e
.byte $41,$45,$49,$4e,$52,$57,$5c,$62,$68,$6e,$75,$7c
.byte $83,$8b,$93,$9c,$a5,$af,$b9,$c4,$d0,$dd,$ea,$f8
freq_table_lo
.byte $07,$17,$27,$39,$4b,$5f,$74,$8a,$a1,$ba,$d4,$f0
.byte $0e,$2d,$4e,$71,$96,$be,$e8,$14,$43,$74,$a9,$e1
.byte $1c,$5a,$9c,$e2,$2d,$7c,$cf,$28,$85,$e8,$52,$c1
.byte $37,$b4,$39,$c5,$5a,$f7,$9e,$4f,$0a,$d1,$a3,$82
.byte $6e,$68,$71,$8a,$b3,$ee,$3c,$9e,$15,$a2,$46,$04
.byte $dc,$d0,$e2,$14,$67,$dd,$79,$3c,$29,$44,$8d,$08
.byte $b8,$a1,$c5,$28,$cd,$ba,$f1,$78,$53,$87,$1a,$10
.byte $71,$42,$89,$4f,$9b,$74,$e2,$f0,$a6,$0e,$33,$20
It has the benefit that the vibrato table can be configured in any way, with different types of commands. The drawbacks are the memory usage of the vibrato table, and the fact that portamento programms are not available at the same time as vibrato. The latter can be circumvented by creating table entries like:
00 dpth 03
01 up 02
02 down 08
03 up 02
04 loop 01
|
| | tlr
Registered: Sep 2003 Posts: 1790 |
Both are interesting.
If I understand hein correctly from my quick look he calculates the add value from the table msb.
$00-$5f = 00<msb>, $60-$bf = <msb>00.
Assuming that gets close to the desired widths it's very clever.
I'm a bit confused about what the optimal tracking for width would be. Is it proportional to the difference to the neighbouring note or is it proportional to the actual frequency?
Also, what do you do if the note changes during the vibrato? An add/sub approach with scaling can get lost in such cases?
I've also gone for a vibrato table approach btw, though mine is a bit more focused on flexibility than speed/size. |
| | Mixer
Registered: Apr 2008 Posts: 452 |
One strategy is to use single octave extended note table. Not the most efficient, but solves some problems.
Assume a frequency table of one octave of 0xc0 length where each 12-tet note is subdivided to 0x10 steps.
The note index will be the high nybble and low nybble will select the detune within one semitone another byte will contain the octave information.
One can then add together arpeggio offset, vibrato offset and portamento offset to that noteindex. And with that number as index - select the frequency value from the frqtable. Once the note frequency within one octave is found - the 16 bit value can be LSR'd or ASL'd to target octave.
To make portamento, one would add a constant value on the portamento offset until target is reached. Vibrato would alternate the vibrato offset between + and - deltas at given periods.
The advantage is that portamento and vibrato will scale right automatically over that exponential notescale.
The disadvantage is that it is slow. Example code is at http://6581.fi/sidwiki/doku.php?id=SID-Knowledge
I apologize that the code-example is missing the required frqtable and octavetable lists, however the idea is there for anyone to improve.
I'd be happy to add other discussed methods to the page as well. |
| | tlr
Registered: Sep 2003 Posts: 1790 |
Interesting solution. One problem is that the slide resolution is (only?) 16 steps per half tone. Another is that the vibrato will be slightly asymmetric as the positive half will be wider than the negative half. This might be perceived as a slight frequency shift upwards during vibrato. |
| | Soren
Registered: Dec 2001 Posts: 547 |
My later routines also use a finetune lookup method, by using extended notefreqtables. Got some additional routines to increase/decrease depth, in case I need that. But the lookup method is pretty fast as you only need to add the finetune values to the freqs of the note before storing in the sid registers.
I usually have a simple routine to handle the finetune values... something like 00,08,10,18,10,08,LOOP-CMD (direction changes after each time the loop happens, BUT one can also use nagative finetune values (over #$80)...
Something in that direction, afair :) |
| | Mixer
Registered: Apr 2008 Posts: 452 |
tlr: Interesting thought that bias, but I don't think that the vibrato will be perceived upward biased. It is the nature of frequency scale to be exponential. c4 to c#4 halftonedelta as register values is bigger than b3 to c4 halftone delta. If anything, this vibrato afaik can be more correct than the constant-delta addition-types. |
| | Stone
Registered: Oct 2006 Posts: 172 |
A classical guitar vibrato stretches the string along its length and so the vibrato centers around the note's frequency. When playing electric guitar, the string moves sideways and the vibrato will generally be biased toward higher frequencies, without it sounding out of tune, so I think that the shape of the waveform that the vibrato produces also matters. I have thought about experimenting with other vibrato shapes than the triangle waveform you get from alternately adding and subtracting a constant value. Haven't gotten around to it yet though.. Interesting topic! |
| | chatGPZ
Registered: Dec 2001 Posts: 11386 |
imho you *want* the vibrato being slightly out of tune - as that greatly contributes to the sound. its somewhat like tuning a 12 string guitar... with the secondary string being perfectly in tune with the first, it just sounds dull and non interesting :=P |
| | Soren
Registered: Dec 2001 Posts: 547 |
Oh yes, reminds me. My simple look-up method also allows me to shape the vibrato, if that wasn't clear from what I wrote.
Sometimes a square shaped vibrato can be a nice thing. Afair some of the grand old computergame composers also did that.
Normally I try to shape vibratos a bit towards a sine wave. |
| | chatGPZ
Registered: Dec 2001 Posts: 11386 |
uhm isnt a square shaped vibrato basically an arpeggio? :) |
| | Dane
Registered: May 2002 Posts: 423 |
The fastest way is definitely to use finetune (add to frq)-tables that loop. The downside is you'll need different tables depending on what note you're on, but if you're not that fussed and want to save rastertime... |
| | tlr
Registered: Sep 2003 Posts: 1790 |
@mixer, groepaz: I guess it depends on the speed of the vibrato. If the vibrato is really fast I think you will notice, although it may be desired like groepaz says.
On synthesizers, at least older analog ones, vibrato is almost always implemented as linear modulation.
@stein: Good point about guitar vibrato. Guitars are very interesting control-wise as the modulation approach is very direct to say the least. It would be interesting to see what kind of frequency modulation curve a normal vibrato run gives. |
| | chatGPZ
Registered: Dec 2001 Posts: 11386 |
<nitpicking>that "e-guitar vibrato" is btw often referred to as "pitch bending", not only because it is more extreme, but also because it is not centered around the base frequency :)</nitpicking> |
| | Hein
Registered: Apr 2004 Posts: 954 |
Quote: Both are interesting.
If I understand hein correctly from my quick look he calculates the add value from the table msb.
$00-$5f = 00<msb>, $60-$bf = <msb>00.
Assuming that gets close to the desired widths it's very clever.
I'm a bit confused about what the optimal tracking for width would be. Is it proportional to the difference to the neighbouring note or is it proportional to the actual frequency?
Also, what do you do if the note changes during the vibrato? An add/sub approach with scaling can get lost in such cases?
I've also gone for a vibrato table approach btw, though mine is a bit more focused on flexibility than speed/size.
The msb is also the lsb indeed (00<msb>) and resulting indices (basenote + depth) $60-$bf give me 16bit frequency add/sub values <msb><lsb>.
The scale will change if the base-note changes, but it's true that for glide (for instance c-3 to c-5), the scale will not change until the base-note (c3) is reset to a new one, for instance with a tie-note or after a glissando command has reached it's target note (c5). The new base-note is the new 0 point from where the add/sub values are fetched from the frequency tables.
I'm not sure what you mean by optimal tracking for width. |
| | tlr
Registered: Sep 2003 Posts: 1790 |
By optimal tracking I was thinking that the difference would have a different slope compared to straight frequencies, but I realize that I've totally forgotten my derivatives. :)
(note/12)
f(note) = f0 * 2
(note/12)
f'(note) = f0 * ln 2 * 2
i.e the difference between any notes a constant distance appart is always proportional to the note halfway between those.
Doing like Hubbard and subtracting just one note away is not 100% accurate though but I guess it doesn't matter. |
| | Hein
Registered: Apr 2004 Posts: 954 |
You can recalculate the slope each frame based on your current frequency and the upcoming frequency, but than it has to be 100% accurate without rounding errors, else your vibrato will detune after a few seconds, I suppose.
In my routine a glide-up can start with an add value of 3 cents each frame, but once it's at the target-note, those 3 cents may have shrunk to a mere 1 cent. :) |
| | Frantic
Registered: Mar 2003 Posts: 1648 |
Just to give some ideas:
If you use flooring when calculating the 16 bit freq values instead of standard rounding you find that the frequency table will actually wrap around nicely, so you can use frequencies in the "lo byte table" for higher values in the hi byte table. (eh.. hard to explain.. tired today). If you look at the commented out lines at the end of the hi byte table you'll see that they are the same as the first lines in the lo byte table, so no need to duplicate them.
So.. first of all, that saves a little bit of RAM since you can use some of the table data both for hi byte values and lo byte values. Then you can also add a bunch of zeroes before the table, to be able to pick sub note values with desired granularity. (e.g. for each octave down in the table you'll have a value that is divided by two, four, eight, etc..) Of course you could also replace the table of zeroes with code that just does a "lda #0" in those cases, to save some table space at the cost of some additional code.
...and you could insert an additional intermediate table to pick a more intelligent set of finetune/vibrato offsets from the freq list. Maybe this way of organizing the tables gives some ideas.. Or not? :) Approaches to vibrato that uses tables run into the problem of extended tables, so I suppose ways of making the tables more compact can be valuable.
(Btw.. the table below was just something I found in an old code file. I don't remember exactly what settings I used for the calculation, so it might be that each octave doesn't even start with a C or such. I post it mainly to illustrate the idea.)
freq_finetunehibytes:
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct0
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct1
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct2
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct3
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct4
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct5
.byte $00,$00,$00,$00,$00,$00,
freq_hibyte: ;floored
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct0
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; oct1
.byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01 ; oct2
.byte $01,$01,$01,$01,$01,$01,$01,$01,$02,$02,$02,$02 ; oct3
.byte $02,$02,$02,$03,$03,$03,$03,$03,$04,$04,$04,$04 ; oct4
.byte $05,$05,$05,$06,$06,$06,$07,$07,$08,$08,$09,$09 ; oct5
.byte $0a,$0a,$0b,$0c,$0d,$0d,$0e,$0f,$10,$11,$12,$13 ; oct6
.byte $14,$15,$17,$18,$1a,$1b,$1d,$1f,$20,$22,$24,$27 ; oct7
; .byte $29,$2b,$2e,$31,$34,$37,$3a,$3e,$41,$45,$49,$4e ; oct8
; .byte $52,$57,$5c,$62,$68,$6e,$75,$7c,$83,$8b,$93,$9c ; oct9
; .byte $a5,$af,$b9,$c4,$d0,$dc,$ea,$f8
freq_lobyte: ;floored as well
.byte $29,$2b,$2e,$31,$34,$37,$3a,$3e,$41,$45,$49,$4e ; oct0
.byte $52,$57,$5c,$62,$68,$6e,$75,$7c,$83,$8b,$93,$9c ; oct1
.byte $a5,$af,$b9,$c4,$d0,$dc,$ea,$f8,$06,$16,$26,$38 ; oct2
.byte $4b,$5e,$73,$89,$a1,$b9,$d4,$f0,$0d,$2c,$4d,$71 ; oct3
.byte $96,$bd,$e7,$13,$42,$73,$a8,$e0,$1b,$59,$9b,$e2 ; oct4
.byte $2c,$7b,$ce,$27,$84,$e7,$51,$c0,$36,$b3,$37,$c4 ; oct5
.byte $59,$f6,$9d,$4e,$09,$cf,$a2,$81,$6d,$67,$6f,$88 ; oct6
.byte $b2,$ed,$3a,$9c,$13,$9f,$44,$02,$da,$ce,$df,$11 ; oct7
.byte $64,$da,$75,$38,$26,$3f,$89,$04,$b4,$9c,$bf,$22 ; oct8
.byte $c8,$b4,$eb,$71,$4c,$7f,$12,$08,$68,$38,$7f,$45 ; oct9
.byte $90,$68,$d6,$e3,$98,$ff,$24,$10
|
|