Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PoroCYon
oidos
Commits
652f52fc
Commit
652f52fc
authored
Apr 04, 2017
by
Aske Simon Christensen
Browse files
Additive synth core in assembly
parent
b3627b7b
Changes
4
Hide whitespace changes
Inline
Side-by-side
synth/Cargo.toml
View file @
652f52fc
...
...
@@ -2,12 +2,16 @@
name
=
"Oidos"
version
=
"0.1.0"
authors
=
[
"Aske Simon Christensen <blueberry@loonies.dk>"
]
build
=
"build.rs"
[dependencies]
vst2
=
{
path
=
"../../rust-vst2"
}
#vst2 = { git = "https://github.com/overdrivenpotato/rust-vst2.git" }
rand
=
"0.3"
[build-dependencies]
nasm-rs
=
{
git
=
"https://github.com/askeksa/nasm-rs"
}
[lib]
name
=
"Oidos"
crate-type
=
["dylib"]
synth/build.rs
0 → 100644
View file @
652f52fc
extern
crate
nasm_rs
;
fn
main
()
{
nasm_rs
::
compile_library
(
"additive.lib"
,
&
[
"src/additive.asm"
]);
println!
(
"cargo:rustc-link-lib=static=additive"
);
}
synth/src/additive.asm
0 → 100644
View file @
652f52fc
%if __BITS__ == 32
%define NAME _additive_core
%define r(n) e%+n
%define PSIZE 4
%define STACK_OFFSET (4*4 + 4)
%else
%define NAME additive_core
%define r(n) r%+n
%define PSIZE 8
%define STACK_OFFSET (4*8 + 2*16 + 8)
%endif
global
NAME
section
sec
text
al
ign
=
1
NAME:
; Disable denormals
push
r
(
ax
)
vstmxcsr
[
r
(
sp
)]
or
dword
[
r
(
sp
)],
0x8040
vldmxcsr
[
r
(
sp
)]
pop
r
(
ax
)
%if __BITS__ == 64
; Save register arguments to stack
mov
[
rsp
+
8
],
rcx
mov
[
rsp
+
16
],
rdx
mov
[
rsp
+
24
],
r8
mov
[
rsp
+
32
],
r9
; Save callee-save registers
sub
rsp
,
2
*
16
vmovupd
[
rsp
+
0
*
16
],
xmm6
vmovupd
[
rsp
+
1
*
16
],
xmm7
%endif
push
r
(
bx
)
push
r
(
bp
)
push
r
(
si
)
push
r
(
di
)
; Initialize
vxorpd
ymm0
,
ymm0
mov
eax
,
1
vcvtsi2sd
xmm1
,
eax
vbroadcastsd
ymm1
,
xmm1
vbroadcastsd
ymm6
,
[
r
(
sp
)
+
STACK_OFFSET
+
6
*
PSIZE
+
0
*
8
]
vbroadcastsd
ymm7
,
[
r
(
sp
)
+
STACK_OFFSET
+
6
*
PSIZE
+
1
*
8
]
; Pointers
mov
r
(
ax
),
[
r
(
sp
)
+
STACK_OFFSET
+
0
*
PSIZE
]
; state_re
mov
r
(
dx
),
[
r
(
sp
)
+
STACK_OFFSET
+
1
*
PSIZE
]
; state_im
mov
r
(
bx
),
[
r
(
sp
)
+
STACK_OFFSET
+
2
*
PSIZE
]
; step_re
mov
r
(
bp
),
[
r
(
sp
)
+
STACK_OFFSET
+
3
*
PSIZE
]
; step_im
mov
r
(
si
),
[
r
(
sp
)
+
STACK_OFFSET
+
4
*
PSIZE
]
; filter_low
mov
r
(
di
),
[
r
(
sp
)
+
STACK_OFFSET
+
5
*
PSIZE
]
; filter_high
; Count
mov
r
(
cx
),
[
r
(
sp
)
+
STACK_OFFSET
+
6
*
PSIZE
+
2
*
8
]
add
r
(
cx
),
3
shr
r
(
cx
),
2
.loop:
; Update oscillator
vmovupd
ymm2
,
[
r
(
ax
)]
vmovupd
ymm3
,
[
r
(
dx
)]
vmulpd
ymm4
,
ymm2
,
[
r
(
bx
)]
vmulpd
ymm5
,
ymm2
,
[
r
(
bp
)]
vmulpd
ymm2
,
ymm3
,
[
r
(
bp
)]
vmulpd
ymm3
,
ymm3
,
[
r
(
bx
)]
vsubpd
ymm2
,
ymm4
,
ymm2
vaddpd
ymm3
,
ymm3
,
ymm5
vmovupd
[
r
(
ax
)],
ymm2
vmovupd
[
r
(
dx
)],
ymm3
; Update filter
vmovupd
ymm4
,
[
r
(
si
)]
vmovupd
ymm5
,
[
r
(
di
)]
vminpd
ymm3
,
ymm4
,
ymm5
vaddpd
ymm4
,
ymm4
,
ymm6
vaddpd
ymm5
,
ymm5
,
ymm7
vmovupd
[
r
(
si
)],
ymm4
vmovupd
[
r
(
di
)],
ymm5
vxorpd
ymm4
,
ymm4
vminpd
ymm3
,
ymm3
,
ymm1
vmaxpd
ymm3
,
ymm3
,
ymm4
; Accumulate filtered oscillator
vmulpd
ymm2
,
ymm2
,
ymm3
vaddpd
ymm0
,
ymm0
,
ymm2
; Advance pointers
add
r
(
ax
),
32
add
r
(
dx
),
32
add
r
(
bx
),
32
add
r
(
bp
),
32
add
r
(
si
),
32
add
r
(
di
),
32
loop
.loop
; Final summation
vextractf128
xmm1
,
ymm0
,
1
vaddpd
xmm0
,
xmm0
,
xmm1
vhaddpd
xmm0
,
xmm0
,
xmm0
; Restore callee-save registers
pop
r
(
di
)
pop
r
(
si
)
pop
r
(
bp
)
pop
r
(
bx
)
%if __BITS__ == 64
vmovupd
xmm6
,
[
rsp
+
0
*
16
]
vmovupd
xmm7
,
[
rsp
+
1
*
16
]
add
rsp
,
2
*
16
%else
; Return result on FP stack
sub
esp
,
8
vmovsd
[
esp
],
xmm0
fld
qword
[
esp
]
add
esp
,
8
%endif
ret
synth/src/oidos_generate.rs
View file @
652f52fc
...
...
@@ -191,15 +191,16 @@ impl SoundGenerator for OidosSoundGenerator {
fn
new
(
param
:
&
OidosSoundParameters
,
tone
:
u8
,
time
:
usize
,
random
:
&
OidosRandomData
)
->
OidosSoundGenerator
{
let
n_partials
=
param
.modes
as
usize
*
param
.fat
as
usize
;
let
n_partials_in_array
=
(
n_partials
+
3
)
&
!
3
;
let
mut
gen
=
OidosSoundGenerator
{
n_partials
:
n_partials
,
state_re
:
Vec
::
with_capacity
(
n_partials
),
state_im
:
Vec
::
with_capacity
(
n_partials
),
step_re
:
Vec
::
with_capacity
(
n_partials
),
step_im
:
Vec
::
with_capacity
(
n_partials
),
filter_low
:
Vec
::
with_capacity
(
n_partials
),
filter_high
:
Vec
::
with_capacity
(
n_partials
),
state_re
:
Vec
::
with_capacity
(
n_partials
_in_array
),
state_im
:
Vec
::
with_capacity
(
n_partials
_in_array
),
step_re
:
Vec
::
with_capacity
(
n_partials
_in_array
),
step_im
:
Vec
::
with_capacity
(
n_partials
_in_array
),
filter_low
:
Vec
::
with_capacity
(
n_partials
_in_array
),
filter_high
:
Vec
::
with_capacity
(
n_partials
_in_array
),
f_add_low
:
(
-
param
.f_sweeplow
*
param
.f_slopelow
)
as
f64
,
f_add_high
:
(
param
.f_sweephigh
*
param
.f_slopehigh
)
as
f64
,
...
...
@@ -248,41 +249,30 @@ impl SoundGenerator for OidosSoundGenerator {
}
}
for
_
in
n_partials
..
n_partials_in_array
{
gen
.state_re
.push
(
0.0
);
gen
.state_im
.push
(
0.0
);
gen
.step_re
.push
(
0.0
);
gen
.step_im
.push
(
0.0
);
gen
.filter_low
.push
(
0.0
);
gen
.filter_high
.push
(
0.0
);
}
gen
}
fn
produce_sample
(
&
mut
self
)
->
f32
{
let
s
=
self
.oscillator_step
()
/
(
self
.n_partials
as
f64
)
.sqrt
();
self
.softclip
(
s
)
as
f32
let
s
=
unsafe
{
additive_core
(
self
.state_re
.as_mut_ptr
(),
self
.state_im
.as_mut_ptr
(),
self
.step_re
.as_ptr
(),
self
.step_im
.as_ptr
(),
self
.filter_low
.as_mut_ptr
(),
self
.filter_high
.as_mut_ptr
(),
self
.f_add_low
,
self
.f_add_high
,
self
.n_partials
)
};
(
s
*
(
self
.gain
/
(
self
.n_partials
as
f64
+
(
self
.gain
-
1.0
)
*
s
*
s
))
.sqrt
())
as
f32
}
}
impl
OidosSoundGenerator
{
fn
oscillator_step
(
&
mut
self
)
->
f64
{
let
mut
s
:
f64
=
0.0
;
for
i
in
0
..
self
.n_partials
{
let
state_re
=
self
.state_re
[
i
];
let
state_im
=
self
.state_im
[
i
];
let
step_re
=
self
.step_re
[
i
];
let
step_im
=
self
.step_im
[
i
];
let
newstate_re
=
state_re
*
step_re
-
state_im
*
step_im
;
let
newstate_im
=
state_re
*
step_im
+
state_im
*
step_re
;
self
.state_re
[
i
]
=
newstate_re
;
self
.state_im
[
i
]
=
newstate_im
;
let
f_low
=
self
.filter_low
[
i
];
let
f_high
=
self
.filter_high
[
i
];
self
.filter_low
[
i
]
=
f_low
+
self
.f_add_low
;
self
.filter_high
[
i
]
=
f_high
+
self
.f_add_high
;
let
f
=
f_low
.min
(
f_high
)
.min
(
1.0
)
.max
(
0.0
);
s
+=
newstate_re
*
f
;
}
s
}
fn
softclip
(
&
self
,
v
:
f64
)
->
f64
{
v
*
(
self
.gain
/
(
1.0
+
(
self
.gain
-
1.0
)
*
v
*
v
))
.sqrt
()
}
extern
"cdecl"
{
fn
additive_core
(
state_re
:
*
mut
f64
,
state_im
:
*
mut
f64
,
step_re
:
*
const
f64
,
step_im
:
*
const
f64
,
filter_low
:
*
mut
f64
,
filter_high
:
*
mut
f64
,
f_add_low
:
f64
,
f_add_high
:
f64
,
n
:
usize
)
->
f64
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment