Giter VIP home page Giter VIP logo

droid-audio's Introduction

What is it?

An Android synthesizer app written in Kotlin and C++. The Kotlin frontend tracks a users' touchscreen input and sends the x,y position to the backend as parameters for custom C++ DSP code. The y position maps to the synth oscillator frequency (musical note/pitch) and the x position maps to the synth filter's cutoff.

Spectral data (harmonics/frequency content) from the synth's output is mapped to RGB color space, encoded as hex values, and sent back to the frontend as parameters for the view's background color gradient.

The frontend Kotlin code is located here in app/src/main/java/com/example/droidaudio/MainActivity.kt.

The native C++ code and DSP algorithms are located here in app/src/main/cpp/.

What does it look and sound like?

droid_synth.mp4

Attn: Github mutes embeds by default. Be sure to unmute the above video.

How does it work?

Audio Engine and Android Oboe

The oboe library is a C++ library created by Google. It makes low latency Android audio apps possible by allowing developers to write DSP code into low level audio callbacks.

I wrote a simple AudioEngine Singleton class (here) which implements the oboe::AudioStreamCallback abstract class, configures some oboe properties in its constructor, and overrides the all important onAudioReady() audio callback method.

With that class in place I was able to begin writing DSP code to make some noise.

The native JNICALL glue that allows data to pass between the front (Kotlin) and backend (C++) is written here in native-lib.cpp.

DSP

Sawtooth Oscillator and DPW

Originally I set out to create a Wavetable style sawtooth oscillator but after some research I bumped into a compelling, progressive method for producing minimally aliased sawtooth waveforms. A PDF of the research paper documenting/publishing the technique can be found here.

The sawtooth oscillator's output is a DPW, a differentiated polynomial (or more specifically in this case, parabolic) waveform.

In brief, the algorithm computes a heavily aliased "naive" sawtooth waveform, then squares that signal (parabolic transformation), and finally differentiates (takes the moving average of) that parabolic signal to reproduce the sawtooth waveform. This time with minimal aliasing.

Higher order polynomial transformations (cubic, quartic, etc) can reduce high frequency aliasing even further but since this synth is limited to the bass register (at most A2 or 110.00hz) the extra cpu cycles would be wasted here.

My implementation can be found in SawOsc.cpp here. Many thanks to Vesa Välimäki, the originator of the technique, for sharing/publishing his discovery.

Low Pass Filter

The LPF was much simpler. I used the venerable RBJ cookbook to create a biquad parametric lowpass filter. My implementation can be found in LPF.cpp here.

Many thanks to Robert Bristow-Johnson for his famous cookbook.

Spectral Data

I used ffts to perform some harmonic analysis on the synth's output signal. The ffts are calculated here in the AudioEngine::updateSpectralData(). More† on the fft library I used later.

The harmonic analysis is performed here in AudioEngine::buildHexCache() and later in that method the results are mapped to RGB color space and finally converted to hex color codes for use on the frontend. Ultimately they're applied to the view's background color gradients so that the color corresponds to the frequency content of the synth's output signal.

FFT Caching

Ffts are computationally expensive so the results are cached instead of recomputed every buffer.

The caching mechanism is configurable. It tracks samples elapsed in a member variable and then calculates time elapsed by scaling samples by the sampling rate. The cache resets after whatever configurable fraction of a second has elapsed.

Likewise, the hex color values are cached by the same mechanism.

†FFT Library

For fft computation I included the dj_fft header only fft library (public domain/MIT licensed). The header also included multi dimensional and gpu accelerated fft methods. I removed those and included only the code I intended to invoke.

Many thanks to Jonathan Dupuy for writing and sharing that concise, useful, and intuitive library.

droid-audio's People

Contributors

bh247484 avatar

Stargazers

SiCoYu avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.