BB01 - Volume Controls

Moderator: DisasterArea

Post Reply
DisasterArea
Posts: 26
Joined: Sat Jul 25, 2020 7:07 pm

BB01 - Volume Controls

Post by DisasterArea »

BUILDING BLOCKS 01 - VOLUME CONTROLS

A volume control is essentially a way to scale a signal somewhere between a minimum and maximum value. If you're used to analog signal design, you'd usually implement this with a voltage divider like this:

Image

Input enters at the Vin port, and output is taken from the Vout port. The ratio of the two impedances Z1 and Z2 determines how much of the signal is allowed to exit Vout.

Vout = Vin * (Z2 / (Z1+Z2))

In practice you'd use a potentiometer to do this, it's the basis of everything in guitar effects. Your guitar probably even has one or two volume controls just like this.

In FXCore, we do have pots but they're not connected to anything in the analog domain, so we have to go through a couple of extra steps to get what we want.

Here's the most basic possible code for a volume control:

Code: Select all

; BUILDING BLOCK 01a - VOLUME CONTROL
; Read input, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, in0	; read input into accumulator
cpy_cs	temp, pot0_smth	; get smoothed value from pot0, will range from 0 to 0.99999
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
Pretty simple, right?

Type or copy that code into your editor of choice and then upload it to your dev board. You should be able to play a signal into in0, output from out0, volume control on pot0. If you don't hear anything, check the troubleshooting steps in BB00 - Getting Started.

This will not amplify / make your input louder, it just passes it on at unity gain or less. If you want to boost things, you'll need to do an extra step.

Code: Select all

; BUILDING BLOCK 01a - VOLUME CONTROL WITH BOOST
; Read input, apply gain, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, in0	; read input into accumulator
sls	acc32, 1	; shift input left by one bit, this is the same as multiplying by 2 or gain of +6dB
cpy_cs	temp, pot0_smth	; get smoothed value from pot0, will range from 0 to 0.99999
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
We use the "barrel shifter" to amplify the input signal. The barrel shifter allows us to take any core register like acc32, r0, etc. and move all of its bits to the left or right. This is the same as multiplying or dividing the signal by powers of two, so "sls 1" means "shift left with saturation one bit." It'll amplify by 2x (+6dB) and if we get over the maximum allowed value it won't roll over (saturation.)

If you want to bump the signal down, you can use the barrel shifter in reverse, shifting right to cut signal:

Code: Select all

; BUILDING BLOCK 01b - VOLUME CONTROL WITH ATTENUATION
; Read input, apply attenuation, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, in0	; read input into accumulator
sra	acc32, 1	; shift input right by one bit, this is the same as divding by 2 or gain of -6dB
cpy_cs	temp, pot0_smth	; get smoothed value from pot0, will range from 0 to 0.99999
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
NOTE: the barrel shifters have several operations that are all pretty similar, the important thing to note is that you should generally use SLS and SRA for audio signals. SL and SR will maybe work but you might have some weird errors or nasty audio as the sign bits aren't always treated as you might expect.

For our last trick, we'll create a volume control with a limited range. This is useful when you don't want the knob to go all the way down to zero, or maybe you don't want it to go quite all the way to maximum

Code: Select all

; BUILDING BLOCK 01c - VOLUME CONTROL WITH LOWER LIMIT
; Read input, limit range, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, pot0_smth	; read smoothed value from pot0, will range from 0 to 0.9999
multri	acc32, 0.8	; multiply pot by 0.8, this means it now ranges from 0 to 0.79999
addsi	acc32, 0.2	; add 0.2 to pot, this means it now ranges from 0.2 to 0.9999
cpy_cs	temp, in0	; read input into accumulator
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
Note that we now have a volume control that ranges from 20% to 100%, so it doesn't go quite down to zero. If you wanted to limit the high end of the pot, you could do this:

Code: Select all

; BUILDING BLOCK 01d - VOLUME CONTROL WITH UPPER LIMIT
; Read input, limit range, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, pot0_smth	; read smoothed value from pot0, will range from 0 to 0.9999
multri	acc32, 0.8	; multiply pot by 0.8, this means it now ranges from 0 to 0.79999
cpy_cs	temp, in0	; read input into accumulator
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
Same idea, but we just multiply the pot and don't add the lower limit back. The pot ranges from 0% - 80% instead. What if you want both limits? Do this:

Code: Select all

; BUILDING BLOCK 01e - VOLUME CONTROL WITH UPPER AND LOWER LIMIT
; Read input, limit range, scale with POT0, write output

.rn	temp	r0

cpy_cs	acc32, pot0_smth	; read smoothed value from pot0, will range from 0 to 0.9999
multri	acc32, 0.6	; multiply pot by 0.6, this means it now ranges from 0 to 0.59999
addsi	acc32, 0.2	; add 0.2 to pot, this means it now ranges from 0.2 to 0.7999
cpy_cs	temp, in0	; read input into accumulator
multrr	temp, acc32	; multiply input * pot, the result will be held in acc32
cpy_sc	out0, acc32	;  write acc32 to output 0
Exactly the same as before, except we multiply by a smaller number so that the total range is lower. We use the MULTRI (multiply immediate) to take our 0-0.9999 value from the pot down to whatever we want, then use ADDSI (add immediate with saturation) to add a fixed value back. Multiply by (maximum - minimum) and then add (minimum,) and you can scale the range of any pot control to what you want.
Post Reply