Tonejs / Tone.js

A Web Audio framework for making interactive music in the browser.
https://tonejs.github.io
MIT License
13.5k stars 981 forks source link

Feature Request: DC Filter #797

Closed Hazmatron7 closed 2 years ago

Hazmatron7 commented 3 years ago

Would be possible to make a DC filter node that blocks dc offsets in audio signal please? This could be very useful.

I did some research about it and a lot of people saying about using a highpass filter with a frequency range about 0 - 20 Hz. https://stackoverflow.com/questions/20948111/how-can-i-remove-a-wandering-dc-offset-from-an-audio-clip

I also found these algorithms: https://github.com/oampo/Audiolet/blob/master/src/dsp/DCFilter.js https://wiki.analog.com/resources/tools-software/sigmastudio/toolbox/filters/dcblocking https://ccrma.stanford.edu/~jos/filters/DC_Blocker.html

Other references: https://en.wikipedia.org/wiki/DC_bias https://www.soundonsound.com/glossary/dc-offset

also Please correct me if I am wrong, but I tried making my own by using the highpass filter method. Unfortuenly I didn't had any audio i could use that already had ad dc offset so I had to record sample and make my own one by using Tone.Subtract(0.5). Then I used Tone.OnePoleFilter({type: "highpass", frequency: 5}); to filter the offset.

These are the results. I used Audacity to show the waveform difference. I used my favorite song 'Daft Punk - One More Time' to test this. πŸ˜„ 🎡

2020-12-02 (3)The Original sample to test it with

2020-12-02

This one above show my version of making a dc offset signal. I'm not sure if I done this correctly, but I tried it anyway.

2020-12-02 (2)

And this one show the result of the filter dc offset using Tone.OnePoleFilter({type: "highpsass"});.

but yeah. Sorry if this is a lot to take in. but is dc filter feature achievable? πŸ˜„

tambien commented 3 years ago

Is the OnePoleFilter code that you showed good for removing the DC offset: Tone.OnePoleFilter({type: "highpass"});?

According to this site that you link to, should be easy enough to implement with the IIRFilterNode. Not sure of the math off the top of my head, but if you could turn the transfer function from that CCRMA link into the proper coefficients, i would gladly accept a PR for such a module.

Hazmatron7 commented 3 years ago

OMG! πŸ˜„ Thank you very much. I'm not a expert at maths and I'd never calculated coefficients before but I will try my best to calculate the them even that means to get some extra help from other people and or more research. πŸ€“ πŸ“š πŸ“– But I will post a comment with coefficient calculations on it when it's done.

Also to answer your question:

Is the OnePoleFilter code that you showed good for removing the DC offset: Tone.OnePoleFilter({type: "highpass"});?

To be honest I'm not entirely sure, maybe. The screenshots from my computer of audacity does show proof of the waveform moving up into position on the 3rd image but when I played it, it sounded ok unlike the 2nd image where it was crackling and popping etc as expected. I only thought of it because the filter doesn't really need a big of a slope and some of the research especially wikipedia says that dc offset can be reduced in real time by using a high pass filter. So I thought I will try using Tone.OnePoleFilter({type: 'highpass'}) (since it also has a -6db rolloff), to see if it works. Trust me after reading about the high pass filter methods and finding those algorithms, I was scratching my head a lot. πŸ€”

Hazmatron7 commented 3 years ago

I got an update for you.

I did some more research and other stuff and I think I found some answers that might help you on how to build it with a IIRFilterNode like you said.

should be easy enough to implement with the IIRFilterNode

Firstly I looked these frequency response graphs to get a basic idea on what where trying to achieve here, so I was a little bit lazy and tried to find a frequency response calculator online and thankfully I did find one and it uses coefficient as input which is good. I played around with it until I found some coefficient numbers that matches magnitude and phase response graphs in CCRMA site for the dc blocker.

In the interactive frequency response grapher site from earlevel.com, try putting in a coefficients side (zeros) to 1.0 for a0 and -1.0 for a1 and on the b coefficients side (poles), put 1.0 for b0 and any number between 0 and -1 for b1 (also known as R). And just you are wondering about why put a number between 0 and -1? Is because when you put a number between 0 to 1 the results doesn't really exactly match the frequency responses and phase response graphs in the CCRMA site. You'll see what I mean you try it. Also the numbers I suggested to you to try on the grapher, I noticed that it's similar to your OnePoleFilter class for the filter type high pass. So mabye could be a consider using. Still not fully sure. I'd do suggest you have try to see the result.

Anyway I also found this:

R = 1 - (2 * Math.PI * frequency / sampleRate);

from this site: https://www.musicdsp.org/en/latest/Filters/135-dc-filter.html. This code came from some comment on the page. I hope this could be useful.

And also I strongly recommend looking at these sites: http://peabody.sapp.org/class/dmp2/lab/dcblock/ https://www.knowles.com/docs/default-source/default-document-library/dc-blocking-filter.pdf?sfvrsn=fdb77b1_6 These 2 sites above both follow the algorithm from the CCRMA site but with different presentation like data tables and graphs and it has diagrams too. I personally think you might find the first URL more useful than the second one.

I don't know if any of these sites below are any useful to you but I put on here just in case. https://www.iro.umontreal.ca/~mignotte/IFT3205/Documents/TipsAndTricks/DCBlockerAlgorithms.pdf http://sam-koblenski.blogspot.com/2015/11/everyday-dsp-for-programmers-dc-and.html https://www.embedded.com/dsp-tricks-dc-removal/

Apologies if you hoping for some code but
I really do hope this info that I found can help you give a bit more of an idea on how to possibly make a dc filter using an IIRFilterNode. If you got any questions feel free to ask. πŸ˜„ πŸ‘

Hazmatron7 commented 3 years ago

Hey

I think i have a solution. look at this image that I took a screenshot of from this site.

image

It basically is saying pretty much the same thing that is says in the CCRMA site. But it if you look at the routings of the feedforward and feedback graph, I think it's safe to say try doing this code:

//a is the parameter. Make sure 'a' is a negative between 0 to 0.999
//feedforward:   [1, -1]
//feedback:      [1, -a]
let filter = Tone.context.createIIRFilter([1, -1], [1, a]);

I do suggest using this calculator to look at it's magnitude and phase response compared to the CCRMA site that show the frequency and phase responses here by putting in the 'a terms (zeros)' 1, -1 and in b the terms (poles), 1 and a negative number between 0 and 0.999. Just in case you ask why a negative number? Is because a positive number on the calculator produces some weird interesting results. Well results that I don't think is what we need for a dc filter. I do suggest have a playground with it though to see what result you can compare with the frequency responses that are in the CCRMA site.

here's and example comparison that i did using the calculator to prove this could be the solution: image

image

If you compared them together, do you see what what I mean?

I do hope this works and a bit more of an idea on how it could be done with an IIRFilterNode. πŸ˜„

tambien commented 2 years ago

moved to #1025