Changed toolchain to "clang", set "-Ofast" so that the code is
compiled with proper optimization, and fixed some code errors
uncovered by clang's more aggressive optimization.
This commit makes the project build on Android Studio. It also deletes
a whole lot of unused code. Further, in this patch, the NEON code is
not build, just C++.
Rolling together a bunch of NEON benchmarks so they can be run from the
command line. This commit adds FM kernel, sawtooth, and ladder filter
benchmarks to the existing FIR and biquad.
The NEON code for computing the matrix for the ladder filter was almost
correct but had some bugs. This patch fixes those and enables it, for
a nice speed improvement (processing time was dominated by the scalar
matrix generation).
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.
The new "zero delay the easy way" provides tools for designing digital
filters based on analog prototypes, and analyzing the results, including
plotting frequency response accurately.
State Variable Filters have many desirable properties, and adapt well
to matrix form. This notebook describes the theory and provides some
measurements of error and behavior under modulation.
The lab/ directory is for experiments and explorations. This is an
IPython notebook suggesting that a matrix-based implementation of biquad
filters may be faster than the traditional method.
This patch changes the ScoreActivity (and the ScoreView that powers it)
to use a generic MidiListener rather than the old
MultiChannelSynthesizer, so that it can play with the new C++ based
sound output module.
The instrument selection maps to MIDI channel, which doesn't actually
change instruments (the synth module is not multitimbral), but this
could be made to work.
Also, the score is stored in protocol buffers, and the plan is for those
to go away, probably replaced by JSON, because of code size and build
difficulty.
A fairly simple feature - preferences for velocity sensitivity, but a
fair amount of UI infrastructure. This patch includes a new
KnobPreference, changes to KnobView to support a horizontal layout
(which works better in a layout with more compressed vertical space),
and of course the plumbing of the preference itself.
Also some rework of the touch handler in the KeyboardView. This patch
simplifies the logic a bit and fixes a long-standing bug in which the
pressure was always read from pointer index 0 rather than the pointer
index of the key being pressed.
Align keyboard at bottom of screen if there's plenty of space (tablets).
Use simpler logic (do as little as possible programatically, use XML to
do heavy lifting).
The main reason for these to be inside the KnobView is so that they can
be part of the touch target for the knob. A more general approach would
be to make the Knob a container that can contain TextView widgets, but
this is simpler.
This adjusts the dimensions of the knobs and scroll strip to be a little
better on both phones and tablets. The knobs look a little small, but
they'll be redesigned soon to work better in smaller sizes.
The first setting is just the keyboard layout, but we'll add lots more
in time (velocity sensitivity). Plus, some synth state (program change
in particular) should persist, and this is a good mechanism.
There are some infelicities: the settings screen doesn't bind the synth
service, so sound pauses. Also, fullscreen is inconsistent and should be
rethought (maybe immersive on KitKat).
New activities can subclass from the SynthActivity, and that will keep
the sound going. We'll actually do something a little different for
preferences, but this will be useful for other activities.
Maximum scroll and zoom range for the keyboard and strip, some style
changes to the knob views (to make them work better for light theme and
also scale for density). This version is basically at least as good as
the old view (although is still lacking octave buttons).
With these changes, there's a max height of 300dp, and a bit more room
in a phone layout (some of the hidden status message widgets were taking
vertical space).
This patch adds text labels (the logic is there for all keys, but we
only draw on C), glissando. and some fine-tuning. The glissando is more
because some touch events are misclassified as move, rather than to
implement actual glissando.
Also, this patch adds velocity, but not yet with adjustable sensitivity.
This patch adds crude touch processing (non multitouch, no tracking),
but it's enough to noodle out melodies to validate the new approach.
The patch also wires up the new view and starts to make some style
changes (holo light theme).
This patch contains a new keyboard view with an adjustable layout.
As of this version, it draws and displays notes from the MIDI keyboard
but doesn't handle any of its own touch events.
The reverse channel from the SynthesizerService to the views has been
refactored a bit so it's just a standard MidiListener interface rather
than a whole bunch of listeners for individual messages.
This patch plumbs note on/off messages from the USB MIDI keyboard to
the piano view, so it's possible to see the notes being played.
Also contains some small UI improvements, like scaling some things to
the device density.
A bunch of improvements to core MIDI handling. New functionality to
decode directly from a byte array (so you don't have to go through
InputStream), as well as more efficient and more concise code for
MessageOutputProcessor, plus some bug fixes.
Note that the tests haven't been run, maybe that would be a good idea.
This patch moves the scan of the USB bus to the service, while plumbing
the display of the permission dialog to the activity that binds it. Also
a little cleanup of the USB device thread (less logging, using a hacky
timeout to make sure the thread gets shut down properly).
This patch moves the connection to the USB MIDI keyboard from a single
activity to the SynthesizerService so that it can run while the user
switches between more than one activity.
Note that in the current state, there are problems when the device is
detached when the service isn't running.
This patch moves the ownership of the NDK synthesizer from an activity
(PianoActivity2) to a service, so that the same synthesizer may be
shared by multiple activities.
Note: this change repurposes an existing class that was used by the old
Java synthesizer. Those code paths will no longer work, and should be
aggressively deleted.
This patch puts up a permissions dialog when needed for connecting a USB
MIDI device. It also avoids scanning the bus when the device is known
from the intent. This should make cases where there are multiple devices
on the USB bus more graceful.
Empirical testing reveals that a smaller buffer size improves two
separate issues. First, it gives much better results on devices that
misreport their buffer size (Moto X is one, and it avoids a crash given
that the reported buffer size was larger than the static allocation for
the synth internal buffer). Second, even on devices that correctly
report the buffer size, it reduces internal buffering in the OpenSL ES
implementation, so this change reduces latency without impacting
robustness.
This patch implements better USB MIDI handling, including listening for
detach, and handling the case where it's connected while the activity is
active.
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.