This change makes the saw do most of the slices without interpolation.
It also uses a fixed frequency for the entire 64 sample buffer, rather
than trying to sweep it linearly (the impact on quality is inaudible).
The calculation of slices is done with actual freq relative to sample
rate, so it should be more robust to sample rate changes. And the
strategy to use is lifted up out of the inner loop.
The total number of slices computed is reduced on both the low and high
ends (from 64 to 36).
Lastly, there's a very clever trick: the slice boundary is placed so
that the interpolation zone falls evenly between notes in 12tet in 44.1
and 48 kHz sampling rates, so the interpolated path will be very
unlikely in practice.
This patch adds an SSE2 variant of the FIR filter, to complement the
existing NEON optimization. This version is written using intrinsics.
Benchmark results: 2.8ns per sample for a 16-tap filter, which is
4x the scalar speed.
This commit is a test implementation of a half-rate FIR structure
(basically a Toom-Cook). It's not bad in the scalar case, but the
benefit is marginal at best in NEON.
This is a FIR filter with NEON speedup. The NEON version has been tested
for accuracy against the scalar one, and there is simple benchmarking
code in place as well.
Extremely highly optimized implementations of the ladder filter in Neon
assembler. The audio loops (both linear and non-linear) are hooked up
and running, while the matrix generation is still running in scalar
code, though the Neon version has been tested and benchmarked.
Performance numbers on Nexus 10: linear audio loop = 22.5 cycles.
Nonlinear audio loop = 62 cycles. Matrix generation = 580 cycles.
Note that the current code will crash on ARM v7 devices without Neon
(for example, Motorola Xoom).
This patch implements nonlinear distortion in the resonant ladder
filter. It's based on the differential equations in the Huovilainen '04
DAFx paper, but using matrix exponential to compute the evolution of the
state variables. The implementation is scalar (and calls into sqrtf),
but designed to be implemented in very efficient SIMD.
This patch changes from the cascaded one pole filter approach to
a matrix based approach, computing the exponential of the Jacobian.
See http://www.kvraudio.com/forum/viewtopic.php?t=385262 for more
discussion of the idea.
This patch contains a test implementation of a nonlinear ladder filter,
closely following Antti Huovilainen's 2004 paper. It's hidden behind an
ifdef, though, as it's not ready for prime time.
This version was published to Play Store as 0.91.
Train patch didn't render right. Should investigate further, but in
the meantime swap out one that does. Also narrow filter range,
increase touch count to 10, and fix pitch env for L4 != 50 case
(take-off patch).
The "com.google" namespace is reserved for official releases, so
renaming to "com.levien".
Also small tweaking to piano2.xml to clean it up for release (arguably
should have been separate commit, but oh well).
This patch implements log2, which is necessary for amplitude modulation
(including amplitude LFO).
Also fixes up command line main.cc to track Dx7 init changes. (The
accuracy test is in that file).
This patch wires up the LFO to the synth unit, and makes it affect pitch
(control over amplitude is not there yet). It also adds LFO delay to the
base LFO implementation, and there are some other cleanups as well (for
example, not unpacking patch data every note).
LFO speeds, delays, and pitch modulation ranges have been calibrated
against the DX7, but testing hasn't been exhaustive.
Finally implements detune (using an approximation, but better than
nothing). Also minor improvements to note generation, including scaling
output level more accurately, and getting rid of dynamic allocations of
note objects.
Add a button to capture raw start and end callback time (just putting it
in a text buffer so it can be copied), which is useful for making plots.
Also a bunch of commented out code to provoke priority inversion or
sudden increases in load (which exercises the governor), again for the
purpose of probing performance and making plots.
I was seeing thread context switches in systrace which looked like they
may have been caused by a mutex held by sprintf, so I replaced it with
a handrolled version (which should be a little faster anyway).
A small amount of stats analysis, mostly max callback time, with simple
display in the UI.
Also improves pow calculation to use lut implementation instead of
math.h pow(), for a speedup somewhere around 20-30%.
The android_glue unit now collects timestamp stats and reports them up
through a ring buffer to the app. The app currently just displays a raw
line in a text view, but we'll expand that out to smarter aggregation.
On API 17+ (JellyBean MR1), get the buffer size and sample rate from the
platform, and use that, rather than hardcoding the defaults. We're still
using an internal buffer size (N) hardcoded to 64, so the amount of
computation per callback is not as consistent as it would be if that
were more flexible.
The FM kernel yields itself well to speedup using NEON assembler. This
patch contains the NEON assembly code, plus C integration code
(including making sure that buffers are aligned to 16 bytes).
This patch adds the low-level implementation of an LFO, with the DX7
waveforms, but doesn't yet contain the note wiring. It also adds a fast
lookup table based exp function, which is mostly used for envelopes.
There are also some build tweaks. It's possible some build files are
out of sync with the source, but at least the Android app seems to
build.
More sophisticated note stealing (better than round robin) and also
implementation of sustain (on midi controller 64). This implementation
matches the DX7 precisely.
Parameter changes and the like should work with unpacked patches,
so now we have an explicit patch unpack. In the future, the unpacking
will move out of the Dx7Note constructor.
This change adds a (single) resonant filter to the C++ synth unit, and
wires up both USB MIDI and on-screen controls for cutoff and resonance.
Also fixes a bug in KnobView which caused the knob value to jump around.
We were only using a very few STL functions (min, max, and iostream for
debug logging). This patch gets rid of those dependencies (implementing
the needed functions in synth.h), and turns on the "all" ABI target, so
that it works with all native architectures supported by the NDK.
This patch wires up pressure sensitivity from the touchscreen. It also
adds simple USB Host mode for MIDI keyboards (tested on M-Audio KeyRig 49
and Akai MPK mini). Finally, it cleans up a bit.
The USB listening thread should be moved out of the activity and into a
service (there can be problems on multiple plug and unplug). But this
should be good enough to play with.