Implement compressor.

This commit is contained in:
Veikko Sariola 2020-05-17 16:37:08 +03:00
parent 71a5a18257
commit fc0ad4c011
9 changed files with 194 additions and 5 deletions

View File

@ -57,8 +57,8 @@ New features since fork
the first thing actually implemented was a set of regression tests to avoid
breaking everything beyond any hope of repair. Done, using CTest.
- **New units**. Bit-crusher, gain, inverse gain, clip, modulate bpm
(proper triplets!)... As always, if you don't use them, they won't be
compiled into the code.
(proper triplets!), compressor (can be used for side-chaining)... As
always, if you don't use them, they won't be compiled into the code.
- **Pattern length does not have to be a power of 2**.
Future goals
@ -68,8 +68,11 @@ Future goals
on CMake and compiles on Windows. Cross-platform NASM/YASM macros have been
drafted and remain to be tested. Once the project is more mature, I will
try compiling on other platforms.
- **Even more opcodes**. At least: compressor (with side-chaining). Maybe
also equalizer.
- **Find a more general solution for skipping opcodes / early outs**. It's
probably a new opcode "skip" that skips from the opcode to the next out in
case the signal entering skip and the signal leaving out are both close to
zero.
- **Even more opcodes**. Maybe an equalizer? DC-offset removal?
- **Support for 64-bit targets**.
- **Browser-based GUI and MIDI instrument**. Modern browsers support WebMIDI,
WebAudio and, most importantly, they are cross-platform and come installed

View File

@ -419,3 +419,56 @@ SECT_DATA(suconst)
%endif
%endif ; DELAY_ID > -1
;-------------------------------------------------------------------------------
; Compressor Tick
;-------------------------------------------------------------------------------
%if COMPRES_ID > -1
SECT_TEXT(sucompr)
EXPORT MANGLE_FUNC(su_op_compressor,0)
fld st0 ; x x
fmul st0, st0 ; x^2 x
%ifdef INCLUDE_STEREO_COMPRES
jnc su_op_compressor_mono
fld st2 ; r l^2 l r
fmul st0, st0 ; r^2 l^2 l r
faddp st1, st0 ; r^2+l^2 l r
call su_op_compressor_mono ; So, for stereo, we square both left & right and add them up
fld st0 ; and return the computed gain two times, ready for MULP STEREO
ret
su_op_compressor_mono:
%endif
fld dword [WRK+su_compres_wrk.level] ; l x^2 x
mov al,1 ; high bits are zero so this is ok. eax = 1 => release
fucomi st0, st1 ; if l > x^2 // we're releasing
jnb su_op_compressor_releasing
xor eax, eax ; eax = 0 => attacking
su_op_compressor_releasing:
fsub st1, st0 ; l x^2-l x
call su_env_map ; c l x^2-l x, c is either attack or release parameter mapped in a nonlinear way
fmulp st2, st0 ; l c*(x^2-l) x
faddp st1, st0 ; l+c*(x^2-l) x
fst dword [WRK+su_compres_wrk.level] ; l'=l+c*(x^2-l), l' x
fld dword [edx+su_compres_ports.threshold] ; t l' x
fmul st0, st0 ; t*t
fucomi st0, st1 ; if threshold < l'
jb su_op_compressor_compress ; then we actually do compression
fstp st0 ; l' x
fstp st0 ; x
fld1 ; 1 x
ret ; return unity gain when we are below threshold
su_op_compressor_compress: ; l' x
fdivrp st1, st0 ; t*t/l' x
fld dword [edx+su_compres_ports.ratio] ; r t*t/l' x
fmul dword [c_0_5] ; p=r/2 t*t/l' x
fxch ; t*t/l' p x
fyl2x ; p*log2(t*t/l') x
jmp MANGLE_FUNC(su_power,0) ; 2^(p*log2(t*t/l')) x
; tail call ; Equal to:
; (t*t/l')^p x
; if ratio is at minimum => p=0 => 1 x
; if ratio is at maximum => p=0.5 => t/x => t/x*x=t
%endif ; COMPRES_ID > -1

View File

@ -344,3 +344,47 @@ struc su_delayline_wrk
.buffer resd MAX_DELAY
.size
endstruc
;-------------------------------------------------------------------------------
; COMPRES effect related defines
;-------------------------------------------------------------------------------
%assign COMPRES_ID -1
%macro USE_COMPRES 0
%if COMPRES_ID == -1
%assign COMPRES_ID CUR_ID
%assign CUR_ID CUR_ID + 2
%xdefine OPCODES OPCODES MANGLE_FUNC(su_op_compressor,0),
%xdefine NUMPARAMS NUMPARAMS 4,
%endif
%endmacro
%macro SU_COMPRES 5
db %2
db %3
db %4
db %5
USE_COMPRES
%xdefine CMDS CMDS COMPRES_ID + %1,
%if %1 == STEREO
%define INCLUDE_STEREO_COMPRES
%endif
%endmacro
%define ATTAC(val) val
%define RELEASE(val) val
%define THRESHOLD(val) val
%define RATIO(val) val
struc su_compres_ports
.attack resd 1
.release resd 1
.threshold resd 1
.ratio resd 1
.ports
endstruc
struc su_compres_wrk
.level resd 1
endstruc

View File

@ -152,7 +152,7 @@ su_transform_values_out:
;-------------------------------------------------------------------------------
SECT_TEXT(supower)
%if ENVELOPE_ID > -1
%if ENVELOPE_ID > -1 ; TODO: compressor also uses this, so should be compiled if either
su_env_map:
fld dword [edx+eax*4] ; x, where x is the parameter in the range 0-1
fimul dword [c_24] ; 24*x

View File

@ -100,6 +100,9 @@ regression_test(test_clip_stereo CLIP)
regression_test(test_crush "VCO_SINE;ENVELOPE;FOP_MULP;INVGAIN" CRUSH)
regression_test(test_crush_stereo CRUSH)
regression_test(test_compressor "" COMPRESSOR)
regression_test(test_compressor_stereo COMPRESSOR)
regression_test(test_filter_band "VCO_SINE;ENVELOPE;FOP_MULP")
regression_test(test_filter_low "VCO_SINE;ENVELOPE;FOP_MULP")
regression_test(test_filter_high "VCO_SINE;ENVELOPE;FOP_MULP")

Binary file not shown.

Binary file not shown.

43
tests/test_compressor.asm Normal file
View File

@ -0,0 +1,43 @@
%define BPM 100
%define USE_SECTIONS
%include "../src/sointu.inc"
SU_BEGIN_PATTERNS
PATTERN 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65,
PATTERN 76, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0,
SU_END_PATTERNS
SU_BEGIN_TRACKS
TRACK VOICES(1),0 ; a very silent voice
TRACK VOICES(1),1 ; a loud one
SU_END_TRACKS
SU_BEGIN_PATCH
SU_BEGIN_INSTRUMENT VOICES(1) ; Instrument0
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(16)
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(16)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(TRISAW)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(TRISAW)
SU_MULP STEREO
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,left) + SEND_POP
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,right) + SEND_POP
SU_END_INSTRUMENT
SU_BEGIN_INSTRUMENT VOICES(1) ; Instrument0
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(128)
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(128)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(SINE)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(SINE)
SU_MULP STEREO
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,left) + SEND_POP
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,right) + SEND_POP
SU_END_INSTRUMENT
SU_BEGIN_INSTRUMENT VOICES(1) ; Global compressor effect
SU_RECEIVE STEREO
SU_COMPRES MONO,ATTAC(32),RELEASE(80),THRESHOLD(32),RATIO(64)
SU_MULP MONO
SU_OUT STEREO, GAIN(128)
SU_END_INSTRUMENT
SU_END_PATCH
%include "../src/sointu.asm"

View File

@ -0,0 +1,43 @@
%define BPM 100
%define USE_SECTIONS
%include "../src/sointu.inc"
SU_BEGIN_PATTERNS
PATTERN 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65,
PATTERN 76, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0,
SU_END_PATTERNS
SU_BEGIN_TRACKS
TRACK VOICES(1),0 ; a very silent voice
TRACK VOICES(1),1 ; a loud one
SU_END_TRACKS
SU_BEGIN_PATCH
SU_BEGIN_INSTRUMENT VOICES(1) ; Instrument0
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(16)
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(16)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(TRISAW)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(TRISAW)
SU_MULP STEREO
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,left) + SEND_POP
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,right) + SEND_POP
SU_END_INSTRUMENT
SU_BEGIN_INSTRUMENT VOICES(1) ; Instrument0
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(128)
SU_ENVELOPE MONO,ATTAC(64),DECAY(64),SUSTAIN(64),RELEASE(64),GAIN(128)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(SINE)
SU_OSCILLAT MONO,TRANSPOSE(88),DETUNE(64),PHASE(0),COLOR(128),SHAPE(64),GAIN(128),FLAGS(SINE)
SU_MULP STEREO
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,left) + SEND_POP
SU_SEND MONO,AMOUNT(128),GLOBALPORT(2,0,receive,right) + SEND_POP
SU_END_INSTRUMENT
SU_BEGIN_INSTRUMENT VOICES(1) ; Global compressor effect
SU_RECEIVE STEREO
SU_COMPRES STEREO,ATTAC(32),RELEASE(80),THRESHOLD(32),RATIO(64)
SU_MULP STEREO
SU_OUT STEREO, GAIN(128)
SU_END_INSTRUMENT
SU_END_PATCH
%include "../src/sointu.asm"