Audio Filters on iOS and OSX

Overview

Audio Filters on iOS and OSX

Implement high quality audio filters with just a few lines of code and Novocaine, or your own audio library of choice.

NVDSP comes with a wide variety of audio filters:

  • All Pass Filter (NVAllpassFilter)
  • Band Pass Filter, 0dB gain (NVBandpassFilter)
  • Band Pass Filter, Q gain (NVBandpassQPeakGainFilter)
  • High Pass Filter (NVHighpassFilter)
  • High Shelving Filter (NVHighShelvingFilter)
  • Low Shelving Filter (NVLowShelvingFilter)
  • Low Pass Filter (NVLowPassFilter)
  • Notch Filter (NVNotchFilter)
  • Peaking EQ Filter (NVPeakingEQFilter)

Combining it with Novocaine (highpass filter)

To start out I recommend you to get a fresh copy of Novocaine and open Novocaine's excellent example project. Then import NVDSP and the Filters folder and start your filtering journey.

// ... import Novocaine here ... 
#import "NVDSP/NVDSP.h"
#import "NVDSP/Filters/NVHighpassFilter.h"

// init Novocaine audioManager
audioManager = [Novocaine audioManager];
float samplingRate = audioManager.samplingRate;

// init fileReader which we will later fetch audio from
NSURL *inputFileURL = [[NSBundle mainBundle] URLForResource:@"Trentemoller-Miss-You" withExtension:@"mp3"];

fileReader = [[AudioFileReader alloc] 
                  initWithAudioFileURL:inputFileURL 
                  samplingRate:audioManager.samplingRate
                  numChannels:audioManager.numOutputChannels];

// setup Highpass filter
NVHighpassFilter *HPF;
HPF = [[NVHighpassFilter alloc] initWithSamplingRate:samplingRate];

HPF.cornerFrequency = 2000.0f;
HPF.Q = 0.5f;

// setup audio output block
[fileReader play];
[audioManager setOutputBlock:^(float *outData, UInt32 numFrames, UInt32 numChannels) {
    [fileReader retrieveFreshAudio:outData numFrames:numFrames numChannels:numChannels];
    
    [HPF filterData:outData numFrames:numFrames numChannels:numChannels];
}];

Note that NVDSP works with raw audio buffers, so it can also work with other libraries instead of Novocaine.

More examples

Peaking EQ filter

// import Novocaine.h and NVDSP.h
#import "NVDSP/Filter/NVPeakingEQFilter.h"
NVPeakingEQFilter *PEF = [[NVPeakingEQFilter alloc] initWithSamplingRate:audioManager.samplingRate];
PEF.centerFrequency = 1000.0f;
PEF.Q = 3.0f;
PEF.G = 20.0f;
[PEF filterData:data numFrames:numFrames numChannels:numChannels];

Lowpass filter

// import Novocaine.h and NVDSP.h
#import "NVDSP/Filter/NVLowpassFilter.h"
NVLowpassFilter *LPF = [[NVLowpassFilter alloc] initWithSamplingRate:audioManager.samplingRate];
LPF.cornerFrequency = 800.0f;
LPF.Q = 0.8f;
[LPF filterData:data numFrames:numFrames numChannels:numChannels];

Notch filter

// import Novocaine.h and NVDSP.h
#import "NVDSP/Filter/NVNotchFilter.h"
NVNotchFilter *NF = [[NVNotchFilter alloc] initWithSamplingRate:audioManager.samplingRate];
NF.centerFrequency = 3000.0f;
NF.Q = 0.8f;
[NF filterData:data numFrames:numFrames numChannels:numChannels];

Bandpass filter

There are two types of bandpass filters:

* 0 dB gain bandpass filter (NVBandpassFilter.h)
* Peak gain Q bandpass filter (NVBandpassQPeakGainFilter.h)
// import Novocaine.h and NVDSP.h
#import "NVDSP/Filter/NVBandpassFilter.h"
NVBandpassFilter *BPF = [[NVBandpassFilter alloc] initWithSamplingRate:audioManager.samplingRate];
BPF.centerFrequency = 2500.0f;
BPF.Q = 0.9f;
[BPF filterData:data numFrames:numFrames numChannels:numChannels];

Measure dB level (ranging from -51.0f to 0.0f)

// import Novocaine.h and NVDSP.h
#import "NVDSP/Utilities/NVSoundLevelMeter.h"
NVSoundLevelMeter *SLM = [[NVSoundLevelMeter alloc] init];
float dB = [SLM getdBLevel:outData numFrames:numFrames numChannels:numChannels];
NSLog(@"dB level: %f", dB);
// NSLogging in an output loop will most likely cause hickups/clicky noises, but it does log the dB level!
// To get a proper dB value, you have to call the getdBLevel method a few times (it has memory of previous values)
// You call this inside the input or outputBlock: [audioManager setOutputBlock:^...

Applying overall gain.

All sample values (typically -1.0f .. 1.0f when not clipping) are multiplied by the gain value.

// import Novocaine.h and NVDSP.h
NVDSP *generalDSP = [[NVDSP alloc] init];
[generalDSP applyGain:outData length:numFrames*numChannels gain:0.8];

Convert stereo (left/right) to mono

This converts a left and right buffer into a mono signal. It takes the average of the samples.

// Deinterleave stereo buffer into seperate left and right
float *left = (float *)malloc((numFrames + 2) * sizeof(float));
float *right = (float *)malloc((numFrames + 2) * sizeof(float));
[generalDSP deinterleave:data left:left right:right length:numFrames];

// Convert left and right to a mono 2 channel buffer
[generalDSP mono:data left:left right:right length:numFrames];

// Free buffers
free(left);
free(right);

Clipping

Multiple peaking EQs with high gains can cause clipping. Clipping is basically sample data that exceeds the maximum or minimum value of 1.0f or -1.0f respectively. Clipping will cause really loud and dirty noises, like a bad overdrive effect. You can use the method counterClipping to prevent clipping (it will reduce the sound level).

// import Novocaine.h and NVDSP.h
#import "NVDSP/Utilities/NVClippingDetection.h"
NVClippingDetection *CDT = [[NVClippingDetection alloc] init];
// ... possible clipped outData ...//
[CDT counterClipping:outData numFrames:numFrames numChannels:numChannels];
// ... outData is now safe ...//

// or get the amount of clipped samples:
 - (float) getClippedSamples:(float *)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels;
// or get the percentage of clipped samples:
 - (float) getClippedPercentage:(float*)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels;
// or get the maximum value of a clipped sample that was found
 - (float) getClippingSample:(float *)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels;

Example project

See /Examples/NVDSPExample for a simple iOS XcodeProject example. Please note the Novocaine bundled with it might be outdated.

A thing to note

The NVDSP class is written in C++, so the classes that use it will have to be Objective-C++. Change all the files that use NVDSP from MyClass.m to MyClass.mm.

Thanks to

Alex Wiltschko - Creator of Novocaine

Yasoshima - Writer of this article, revealing how vDSP_deq22 works. (and google translate, I don't speak Japanese)

hrnt - Helpful on IRC #iphonedev (freenode)

Comments
  • Thread safety and efficiency

    Thread safety and efficiency

    First of all, thanks for putting this code up on the Internet, I'm pretty sure it helped a lot of people in making their first steps into iOS/OSX audio, like it did for me. However, I decided to switch to The Amazing Audio Engine and my own implementation of filters (like NVDSP did with Novocaine) and I thought I'd share why.

    First reason is thread safety: neither Novocaine nor NVDSP are thread safe as far as I can tell. Because audio processing happens in a separate high-priority thread, while e.g. filter parameters can be changed from the main thread, you need to design your classes with thread safety in mind. For example, when a user changes one of the peaking filter parameters and while you are calculating your 5 coefficients, the audio thread may use them for filtering the audio. These race conditions may not be so rare as you might think, especially with smaller buffer sizes on OS X, but they won't always result in audible glitches. In this particular case, if you want to avoid locking, you need to have two copies of the coefficients and also have an atomic flag that indicates (using OSAtomicX()) whether they were copied to the real-time thread or not. As one example of what could be done.

    But then comes the problem of efficiency and again, neither Novocaine nor NVDSP were designed with efficiency in mind. For example, you do dynamic allocation of buffers in each cycle and it's just a horrendously bad thing to do. Let alone that Objective-C messaging is scattered everywhere in real-time code. On top of that, if you want to implement a multi-band EQ you could avoid copying vDSP_deq22() buffers for each of the filters by swapping them. I've noticed a dozen of other things that could've been optimized.

    TAAE by contrast is made with these things in mind. The code that uses TAAE may be a little uglier, but at least all real-time code is pure C, no dynamic allocation and no I/O happening there, and the documentation stresses that user code that's executed in the real-time thread should adhere to the same principles. TAAE can even give you warnings in Debug mode that your real-time routine is taking too long to execute.

    Anyway, like I said I'm still grateful to those who wrote and contributed to Novocaine and NVDSP but once you consider efficiency and thread safety (you don't want to drain your users' phone battery and you don't want them to hear occasional glitches, right?) you realize that these two libraries fall short. Fixing these things though might require a serious effort, if not a complete revamp. In any case unfortunately I won't be contributing to these repositories but I'm willing to help to anyone who'd consider redoing them.

    Thanks again, and have a nice coding!

    opened by crontab 11
  • Filter Save | Suggestion

    Filter Save | Suggestion

    Hi is there a way we can load an audio in memory using Novocaine and then applying filters to it and once we are done we can save the modified sound (including filters) by making a new file?

    currently all I could find is to apply NVDSP filters on the currently playing audio stream. Is there any way to save this modified audio stream? If not then are you planing to support this feature in future? If yes, when can we be able to have that feature?

    opened by ghost 11
  • Feed it the next song...

    Feed it the next song...

    I also can't figure out how to feed it another song. It plays one song, then stops.

    • (void)updateWithMediaItemURL:(NSURL *) itemURL {

      _fileReader = [[AudioFileReader alloc] initWithAudioFileURL:itemURL samplingRate:audioManager.samplingRate numChannels:audioManager.numOutputChannels];

        __block float lastTimeLeft = - 1.0f;
        float timeLeft = self.fileReader.duration - [self.fileReader getCurrentTime];
      
        if ( timeLeft > 1.1) { //&& timeLeft != lastTimeLeft
            lastTimeLeft = timeLeft;
        } else {
            [self pause];
      
            if (!self.fileReader.playing) {
                audioManager.outputBlock = nil;
                [self.mediaDelegate nextSongPlay];
            }
        }
        NSLog(@"%f", timeLeft);
      
        [audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)   {
        [self.fileReader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels];
      
        PEQ.G = PEQ_centerFrequency;
        [PEQ filterData:data numFrames:numFrames numChannels:numChannels];
        [CDT counterClipping:data numFrames:numFrames numChannels:numChannels];
      

      }]; }

    opened by doriansgithub 8
  • BandRejectFilter, how to apply two filters at once and how to filter vocals?

    BandRejectFilter, how to apply two filters at once and how to filter vocals?

    Is there any privilege to apply band reject filter? or Is it possible to apply two filters at once? I tried it but with no success. I think it should have band reject filter too.

    question 
    opened by TanejaArun 6
  • NVDSP not work with audioUnit render?

    NVDSP not work with audioUnit render?

    I wrote a recorder in remote IO Unit.I want to calculate the sound level of the samples in the render callback. I found NVDSP project have an util method to getDBLevel:

    - (float) getdBLevel:(float *)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels;
    

    So, I try to pass the AudioBuffer as parameters of this method:

    static OSStatus performRender(void *inRefCon,
                              AudioUnitRenderActionFlags    *ioActionFlags,
                              const AudioTimeStamp      *inTimeStamp,
                              UInt32                        inBusNumber,
                              UInt32                        inNumberFrames,
                              AudioBufferList           *ioData){
    
    AudioBuffer buf = ioData->mBuffers[0];
    float db = [[[NVSoundLevelMeter alloc] init] getdBLevel:buf.mData numFrames:inNumberFrames numChannels:buf.mNumberChannels];
    

    but this is not work as expect, it always return -50db.

    Any idea?

    question 
    opened by jeffkit 6
  • Possible bug in NVDSP.mm when copying the results back to audio buffer

    Possible bug in NVDSP.mm when copying the results back to audio buffer

    In method filterContiguousData (line 81) when you copy the results back:

    memcpy(data, tOutputBuffer, numFrames * sizeof(float));
    

    I think it should be

    memcpy(data, tOutputBuffer + 2, numFrames * sizeof(float));
    

    I haven't tested this yet, but if it is a bug it may go unnoticed in audio.

    Many other examples on the Net do this. See e.g. http://vboehm.net/2015/04/using-vdsp_deq22-correctly/

    opened by crontab 4
  • Some Interruption when the app go to background

    Some Interruption when the app go to background

    Hello, I'm using NVDSP with my application and I have a little problem with it when the app go to background, unlike your exemple, my application keep the audio playing when the app go to background, and occasionally the audio played in an interrupted manner. I see the same problem when I run your exemple, The audio Is automatically played, I tap the home button and Just before the app go to background the audio play with interruption. Any Idea why this is happening please ?

    opened by baderbenzribia 3
  • MTAudioProcessingTap to NVDSP

    MTAudioProcessingTap to NVDSP

    Hi! I am trying to apply an EQ on a iOS AVPlayer. I know that it is not the best way to go, but i don't have room to choose the player used here.

    From what i found here: [https://chritto.wordpress.com/2013/01/07/processing-avplayers-audio-with-mtaudioprocessingtap/] it is possible to extract raw audio data from AVPLayer using MTAudioProcessingTap. Using this, i end up with a "process" method which is the way to treat raw data from AVPlayer. In the example below this "process" method apply vDSP_vsmul on the audio flux (it's a simplified example from the link attached).

    If i am right, i should be able to use your Filters here instead of vDSP_vsmul. My goal is to make a 10(ish)-band EQ (with your PeakingEQ which seems nice)... Could you point me on how to achieve this inside that "process" function ? I am a bit lost with those vDSP / Filters stuffs... but i feel i am not far from it: The processing in your library is vDSP based too, so the works done by your library could seat here..

    // Function called by MTAudioProcessingTap allowing treatment of audio flux..
    void process(
        MTAudioProcessingTapRef tap, 
        CMItemCount numberFrames,
        MTAudioProcessingTapFlags flags, 
        AudioBufferList *bufferListInOut,
        CMItemCount *numberFramesOut, 
        MTAudioProcessingTapFlags *flagsOut)
    {
        // Error detection
        OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut);
        if (err) NSLog(@"Error from GetSourceAudio: %ld", err);
    
       // Arbitrary treatment given as exemple
        float scalar = 5;
        vDSP_vsmul(bufferListInOut->mBuffers[0].mData, 1, &scalar, bufferListInOut->mBuffers[0].mData, 1, bufferListInOut->mBuffers[0].mDataByteSize / sizeof(float));
        vDSP_vsmul(bufferListInOut->mBuffers[1].mData, 1, &scalar, bufferListInOut->mBuffers[1].mData, 1, bufferListInOut->mBuffers[1].mDataByteSize / sizeof(float));
    }
    

    Thank you !

    Best Regards,

    Thomas

    question 
    opened by Maigre 3
  • Trying to apply Equaliser

    Trying to apply Equaliser

    Hello Dear,

    I am trying to build 10 band equaliser. Well i copy pasted Equaliser.mm's code in "viewWillAppear". And added 9 more Sliders in xib file. and changed IBAction code too.

    (void)HPFSliderChanged:(UISlider *)sender {
     PEQ[sender.tag - 1].centerFrequency = sender.value;
     NSLog(@"%f",sender.value);
     }
    

    I wanna know am i doing right ? and the what will be range of the Sliders? Like in HPF slider range is 2k to 8k Thanks

    opened by OmerObaid 3
  • 10-band equalizer example sounds weird

    10-band equalizer example sounds weird

    I'm not really familiar with audio filters, so I looked at your example and in it was what seemed to be exactly what I'm looking for, it had all the right frequencies (and the comment at the top said it was a 10-band equalizer).

    But I tried it out and something just doesn't sound right about it..... the implementation in this one sounds weird compared to applications like mpv ~~and winamp~~ (nevermind, winamp sounds just as weird). Is that just how a PeakingEQFilter works? Should I be using another filter along with the PeakingEQFilters? And why did you set the Q-factor to 2?

    Here's mpv's implementation of it's equalizer: https://github.com/mpv-player/mpv/blob/master/audio/filter/af_equalizer.c

    question 
    opened by rweichler 3
  • How to get audio data to use from microphone.

    How to get audio data to use from microphone.

    Hi, I'm working on iOS application which is written in Swift 5. I'm looking to create A weight bandpass filter. My query is that currently, I am receiving audio samples through a microphone using tap. How can I use a High bandpass filter on an audio stream coming from the microphone to evaluate dB value?

    opened by jogasinghbajwa 1
  • BandPass filter help

    BandPass filter help

    Hey there! I'm trying to use your bandpass filter to filter an array of values (I'm trying to do heart beat detection). I'm new to signal processing and I was wondering if you could explain how to get the coefficients within your code. I see they are being called in this example on stackoverflow: https://stackoverflow.com/questions/10604690/noise-distortion-after-doing-filters-with-vdsp-deq22-biquad-iir-filter/10608609#10608609. I'm trying to create a bandpass filter between 0.667 Hz and 4.167 Hz. I have a sample rate of 30 frames per second. If you have any tips or can confirm if I could use your framework to do this that would be helpful! Thank you!

    // import Novocaine.h and NVDSP.h #import "NVDSP/Filter/NVBandpassFilter.h" NVBandpassFilter *BPF = [[NVBandpassFilter alloc] initWithSamplingRate:audioManager.samplingRate]; BPF.centerFrequency = 2500.0f; BPF.Q = 0.9f; [BPF filterData:data numFrames:numFrames numChannels:numChannels];

    opened by ksuhr1 0
  • RingBuffer

    RingBuffer

    We need to comment out the following in the RingBuffer, or we get errors.

    #ifdef __cplusplus

    #endif

    Does anyone know why this is the case? We can't init the RingBuffer with the error.

    opened by doriansgithub 2
  • Digital Room Correction

    Digital Room Correction

    Any idea on how complicated it would be to add support for digital room correction filter. http://en.wikipedia.org/wiki/Digital_room_correction

    Also how about a decay filter?

    enhancement 
    opened by neox38 1
  • Noise Filtering

    Noise Filtering

    How shall i proceed with Noise filtering from the Audio using NVDSP. Please show me some way to achieve that. Also i want to recognise a sound pattern in the recorder audio and remove it from that audio file.

    enhancement 
    opened by puneetchd 6
Releases(v0.0.1)
Owner
Bart Olsthoorn
PhD Student @ Nordic Institute for Theoretical Physics
Bart Olsthoorn
AudiosPlugin is a Godot iOS Audio Plugin that resolves the audio recording issue in iOS for Godot Engine.

This plugin solves the Godot game engine audio recording and playback issue in iOS devices. Please open the Audios Plugin XCode Project and compile the project. You can also use the libaudios_plugin.a binary in your project.

null 3 Dec 22, 2022
The Amazing Audio Engine is a sophisticated framework for iOS audio applications, built so you don't have to.

Important Notice: The Amazing Audio Engine has been retired. See the announcement here The Amazing Audio Engine The Amazing Audio Engine is a sophisti

null 523 Nov 12, 2022
AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS, and tvOS.

AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS (including Catalyst), and tvOS. Installation To add AudioKit

AudioKit 9.5k Dec 31, 2022
Voice Memos is an audio recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Swift.

VoiceMemos Voice Memos is a voice recorder App for iPhone and iPad that covers some of the new technologies and APIs introduced in iOS 8 written in Sw

Zhouqi Mo 322 Aug 4, 2022
AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

AudioPlayer AudioPlayer is a simple class for playing audio in iOS, macOS and tvOS apps.

Tom Baranes 260 Nov 27, 2022
Swift audio synthesis, processing, & analysis platform for iOS, macOS and tvOS

AudioKit AudioKit is an audio synthesis, processing, and analysis platform for iOS, macOS (including Catalyst), and tvOS. Installation To add AudioKit

AudioKit 8.7k Sep 30, 2021
Painless high-performance audio on iOS and Mac OS X

An analgesic for high-performance audio on iOS and OSX. Really fast audio in iOS and Mac OS X using Audio Units is hard, and will leave you scarred an

Alex Wiltschko 2.2k Nov 23, 2022
AudioPlayer is syntax and feature sugar over AVPlayer. It plays your audio files (local & remote).

AudioPlayer AudioPlayer is a wrapper around AVPlayer. It also offers cool features such as: Quality control based on number of interruption (buffering

Kevin Delannoy 676 Dec 25, 2022
YiVideoEditor is a library for rotating, cropping, adding layers (watermark) and as well as adding audio (music) to the videos.

YiVideoEditor YiVideoEditor is a library for rotating, cropping, adding layers (watermark) and as well as adding audio (music) to the videos. YiVideoE

coderyi 97 Dec 14, 2022
App for adding and listening audio files

SomeSa SomeSa (самса) – приложение, позволяющее загружать и воспроизводить произвольные аудиофайлы. Протестировано на форматах файлов .wav и .mp3, раз

Yegor Dobrodeyev 0 Nov 7, 2021
Simple command line utility for switching audio inputs and outputs on macOS

Switch Audio Simple command line utility for switching audio inputs and outputs

Daniel Hladík 3 Nov 22, 2022
This app demonstrates how to use the Google Cloud Speech API and Apple on-device Speech library to recognize speech in live recorded audio.

SpeechRecognitionIOS This app demonstrates how to use Google Cloud Speech API and Apple on-device Speech library to recognize speech in live audio rec

Josh Uvi 0 Mar 11, 2022
Beethoven is an audio processing Swift library

Beethoven is an audio processing Swift library that provides an easy-to-use interface to solve an age-old problem of pitch detection of musical signals.

Vadym Markov 735 Dec 24, 2022
FDWaveformView is an easy way to display an audio waveform in your app

FDWaveformView is an easy way to display an audio waveform in your app. It is a nice visualization to show a playing audio file or to select a position in a file.

William Entriken 1.1k Dec 21, 2022
SwiftAudioPlayer - Swift-based audio player with AVAudioEngine as its base

SwiftAudioPlayer Swift-based audio player with AVAudioEngine as its base. Allows for: streaming online audio, playing local file, changing audio speed

null 417 Jan 7, 2023
A drop-in universal library allows to record audio within the app with a nice User Interface.

IQAudioRecorderController IQAudioRecorderController is a drop-in universal library allows to record and crop audio within the app with a nice User Int

Mohd Iftekhar Qurashi 637 Nov 17, 2022
Audio visualisation of song

SonogramView Audio visualisation of song Requirements iOS 8.0+ macOS 10.10+ Xcode 8.0+ Installation: Manually First Check SonogramView.swift or MacSon

Gleb Karpushkin 66 Nov 3, 2022
AIB indicates for your app users which audio is playing. Just like the Podcasts app.

Audio Indicator Bars for iOS and tvOS Indicates for your app users which audio is playing. Just like the Podcasts app. Index Requirements and Details

Leonardo Cardoso 285 Nov 23, 2022
Subsonic is a small library that makes it easier to play audio with SwiftUI

Subsonic is a small library that makes it easier to play audio with SwiftUI

Paul Hudson 218 Dec 16, 2022