Octave Down Patch - OC-2 & U-Boat Style

Algorithm development and general DSP issues

Moderator: frank

Post Reply
Philcaster
Posts: 4
Joined: Mon Feb 24, 2020 2:12 pm

Octave Down Patch - OC-2 & U-Boat Style

Post by Philcaster »

First time posting code here! I was working on a vero build of a chopped OC-2 (still haven't gotten around to finishing it) and got really curious about how it worked. That led me to the Valve Wizard U-Boat page. After reading it about 4 times, I started to have an idea of what he was talking about, and then realized everything he described I knew how to do roughly on the fv-1.

So this is a patch that tries to implement the U-Boat method for octave down as described in the article.

It came out fairly well in my opinion, on guitar or bass. The tracking of course isn't perfect, but to me it's very usable.

I borrowed a friend's OC-2 to compare. There's a comment in the Valve Wizard U-Boat article that says that the boss method (inverting at the peaks) has a smoother sound, the u-boat method (invert on zero crossing) has more harmonic content. My code is the u-boat way since he said that way is easier to implement with decent tracking. Playing this patch next to the OC-2, the OC-2 is definetely smoother, and tracks slightly better. On bass, you can dial it in to sound kinda subtle (like your bass tone but fatter). But, I also kinda like the more aggressive tone of this code. I haven't played a u-boat circuit to compare.

As an afterthought, I threw on a rectify dirty octave up (absa code line), like a green ringer, controlled by pot2. It's kind of fun to blend with the octave down.

I was also helped by reading this old code post by Don Stavely, has a lot of similarities to what I wanted to do, so it helped me get my bearings a bit.
http://www.spinsemi.com/forum/viewtopic.php?t=161
--Feb 17 code post

I'd love to hear any feedback if you try it out. The oct down can get fairly loud, so take it easy, especially w/ guitar amps that weren't designed to handle bass.

Oh yeah, also, I know the LPFs can be done easier. I forgot how, and had this brute force way written down, never went back and optimized it.

Code: Select all

;Phil's Octave Down (OC-2 style) & Up (Green Ringer style)
;After reading valve wizard's u-boat page, I decided to try to implement the same algorithm in fv-1.
;The goal was a faster, funkier octave than the typical ramp delay address type, for both bass and guitar
;Tracking on the octave down is not perfect, but decent in my opinion
;As an afterthought I added the 'rectified' octave up (just an absa command), sounds like a green ringer.
;I think these 2 effects (up and down) compliment each other nicely for a synthy texture

;pot0 - clean
;pot1 - oct down
;pot2 - oct up


equ sig		reg0		;input after filter
equ sig_inv	reg1		;input after filter, iverted
equ square 	reg2		;square wave (generated from input)
equ sq_dn	reg3		;square wave divided for oct down
equ lpf1_temp	reg4
equ lpf2_temp	reg5
equ lpf3_temp	reg6
equ lpf_k2	reg7
equ env		reg8
equ peak_flag	reg9
equ prev	reg10
equ prev_sq	reg11
equ sig_dn	reg12
equ lpf4_temp	reg13
equ lpf5_temp	reg14
equ down_final	reg15
equ up_final	reg16


skp run, START
sof 0, 0.99
wrax sq_dn, 0
sof 0, 0.174			;puts lpf around 1kHz
wrax lpf_k2, 0
START:

;-----setup previous values to detect zero crossings-----
ldax sig
wrax prev, 0
ldax square
wrax prev_sq, 0

;-----convert input to amplified, filtered, balanced-----
ldax adcl
sof -2, 0
sof -2, 0			;gain 4x

rdax lpf1_temp, -1		;3x 1st order LPF at 1kHz
mulx lpf_k2
rdax  lpf1_temp, 1
wrax lpf1_temp, 1 

rdax lpf2_temp, -1
mulx lpf_k2
rdax lpf2_temp, 1
wrax lpf2_temp, 1

rdax lpf3_temp, -1
mulx lpf_k2
rdax lpf3_temp, 1
wrax lpf3_temp, 1

wrax sig, -1			;write sig (amplifed and filtered)
wrax sig_inv, 1			;write inverted 


;-----envelope folower-----
absa				;sig_inv is in the ACC (could be either sig or sig_inv)
rdax env, -1			;subract env value
skp neg, NO_PEAK		;if negative, signal is less than env
;---it is a peak (positive or negative)
sof 0, 0.99
wrax peak_flag, 0
ldax sig_inv
absa
wrax env, 0
skp ZRO, PEAK_OVR
NO_PEAK:
ldax env
sof 0.98, 0			;decay envelope follower
wrax env, 0

PEAK_OVR:


;-----set square wave if zero crossing (& prove peak)-----
ldax prev
skp neg, PRV_NEG
ldax sig
skp gez, CRS_OVR
ldax peak_flag			;peak must have been reached to trigger crossing
skp zro, CRS_OVR
sof 0, 0.1
wrax square, 0
wrax peak_flag, 0		;reset peak flag
skp zro, CRS_OVR
PRV_NEG:
ldax sig
skp neg, CRS_OVR
ldax peak_flag
skp zro, CRS_OVR
sof 0, -0.1
wrax square, 0
wrax peak_flag, 0		;reset peak flag

CRS_OVR:


;-----flip flop sq_down every positive zero crossing-----
ldax square
skp neg, FLP_OVR
ldax prev_sq
skp gez, FLP_OVR
;---it is positive zero crossing
ldax sq_dn
sof -1, 0
wrax sq_dn, 0
FLP_OVR:

ldax sq_dn
skp neg, INV_CYCLE
ldax sig
wrax sig_dn, 0
skp zro, DN_OVR
INV_CYCLE:
ldax sig_inv
wrax sig_dn, 0
DN_OVR:

ldax sig_dn
rdax lpf4_temp, -1		;2x 1st order LPF at 1kHz (remove clicks from stitching signals)
mulx lpf_k2
rdax  lpf4_temp, 1
wrax lpf4_temp, 1 

rdax lpf5_temp, -1
mulx lpf_k2
rdax lpf5_temp, 1
wrax lpf5_temp, 1

mulx pot1
wrax down_final, 0

;-----octave up (rectify, like green ringer)-----
ldax adcl
absa
mulx pot2
wrax up_final, 0

;-----mix final signals-----
ldax adcl
mulx pot0			;pot0 mixes the dry signal
rdax down_final, 1
rdax up_final, 1
wrax dacl, 0
Post Reply