|
|
|
11-02-2018, 06:08 PM
|
#1
|
Human being with feelings
Join Date: May 2018
Location: Los Angeles
Posts: 1,721
|
Math Gurus -- how to calculate slope of 2 samples in AudioAccessor
Hi Gurus,
I'm getting my feet wet with AudioAccessor.
As a fun project I'm going to try to do a VERY SIMPLE click detection algo. Simply have a threshold for change in slope between pairs of points -- this should work for tonal instruments.
I know slope = ∆y/∆x, and I know what the ∆y will be (between -1 and 1)... but what should I use as a x unit to get a decent slope? Is there a convention out there in digital audio land?
I'll be operating in 48k.
Thanks for any insight.
Cheers!
__________________
Cheers... Andrew K
Reaper v6.80+dev0621 - June 21 2023 • Catalina • Mac Mini 2020 6 core i7 • 64GB RAM • OS: Catalina • 4K monitor • RME RayDAT card with Sync Card and extended Light Pipe.
|
|
|
11-02-2018, 06:46 PM
|
#2
|
Human being with feelings
Join Date: Dec 2012
Posts: 7,294
|
x is in samples, and the easiest way to do it is just use 1. Decide the loudest 20kHz signal you want to be able to pass without triggering whatever you're doing. The peak-to-peak value of that will be your "slope" threshold.
I have a JS Slew Rate Limiter that "talks" in Volts/second so that I can sort of emulate various parts of a circuit by checking the data sheet. I do the math to turn volts into floating point numbers and seconds into seconds and then divide them to find the limit. It actually works really well for de-clicking way before you get to noticeable high frequency distortion, but I think the version I have in the stash is all messed up. I should upload the new one. It's curvy.
|
|
|
11-02-2018, 09:40 PM
|
#3
|
Human being with feelings
Join Date: May 2018
Location: Los Angeles
Posts: 1,721
|
Quote:
Originally Posted by ashcat_lt
x is in samples, and the easiest way to do it is just use 1. Decide the loudest 20kHz signal you want to be able to pass without triggering whatever you're doing. The peak-to-peak value of that will be your "slope" threshold.
I have a JS Slew Rate Limiter that "talks" in Volts/second so that I can sort of emulate various parts of a circuit by checking the data sheet. I do the math to turn volts into floating point numbers and seconds into seconds and then divide them to find the limit. It actually works really well for de-clicking way before you get to noticeable high frequency distortion, but I think the version I have in the stash is all messed up. I should upload the new one. It's curvy.
|
Thanks ashcat_lt!
I was thinking of maybe using 1 also... in which case I could just ignore the divisor.
I'll give it a shot and see what I come up with. I'm certain it won't be as easy it is seems in my head LOL
Cheers!
__________________
Cheers... Andrew K
Reaper v6.80+dev0621 - June 21 2023 • Catalina • Mac Mini 2020 6 core i7 • 64GB RAM • OS: Catalina • 4K monitor • RME RayDAT card with Sync Card and extended Light Pipe.
|
|
|
11-03-2018, 12:56 AM
|
#4
|
Human being with feelings
Join Date: Aug 2013
Location: Bowral, Australia
Posts: 1,643
|
Yes, X should be 1 if analysing per sample, but I think your question is really what value to use for y? The simple answer is make it a variable and experiment.
|
|
|
11-03-2018, 04:09 AM
|
#5
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,900
|
You don't need "slope", you are drawing a charts :P
Every samples are spaced by the same unit : 1 samples.
So just make the difference between two samples and you will have what you need.
|
|
|
11-03-2018, 06:41 AM
|
#6
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Simple saw wave will trigger thousands of points, so you have to filter them by some time area, ratio click gain relative to previous/next samples (or/and analyze spectrum around founded point to make sure click is ot a part of original signal if you want to go far than "very simple").
|
|
|
11-03-2018, 07:36 AM
|
#7
|
Human being with feelings
Join Date: Aug 2013
Location: Bowral, Australia
Posts: 1,643
|
My guess is that the slope (difference between two samples) that constitutes a click will vary with amplitude. You could possibly compare the slope with that of a sine wave of some reference 'click frequency'. To complicate matters, what constitutes a click may be dependant on context, (think MPL's example of a sawtooth wave). If you have examples of the kind of clicks you are looking to detect, it may be worth examining the waveforms of those to get some clues as to what you are looking for.
|
|
|
11-03-2018, 07:52 AM
|
#8
|
Human being with feelings
Join Date: Dec 2012
Posts: 7,294
|
Honestly I think what you want to look for is sudden large changes in the slope. Take a look at the JS trainsient plug (or my Transient Splitter which should be in the stash). It keeps two running averages - one shorter than the other. When the difference (or ratio? I'd have to look again) between those two envelopes is significantly different, it counts as a transient. That's about exactly what you want, I think.
|
|
|
11-03-2018, 08:05 AM
|
#9
|
Human being with feelings
Join Date: May 2018
Location: Los Angeles
Posts: 1,721
|
Thanks for all the input guys!!
As MPL said, a sawtooth would indeed create a marker at every cycle, however, I'm dealing with acoustic tonal instruments. Looking at that clicks (I can post a picture later... not in studio now), there is a pattern of drastic change of slope and direction also... while everything else is very smooth by comparison.
Quote:
Originally Posted by ashcat_lt
Honestly I think what you want to look for is sudden large changes in the slope. Take a look at the JS trainsient plug (or my Transient Splitter which should be in the stash). It keeps two running averages - one shorter than the other. When the difference (or ratio? I'd have to look again) between those two envelopes is significantly different, it counts as a transient. That's about exactly what you want, I think.
|
Yes... I do the same sort of of trick when coding technical analysis indicators for the stock market. The trick is reducing the "noise". I'm not well versed enough in higher maths to do the proper white-paper algos I've seen involving cycle pattern comparison... that's for the RX people to do
Thanks again. I will give it a shot tomorrow (busy weekend).
__________________
Cheers... Andrew K
Reaper v6.80+dev0621 - June 21 2023 • Catalina • Mac Mini 2020 6 core i7 • 64GB RAM • OS: Catalina • 4K monitor • RME RayDAT card with Sync Card and extended Light Pipe.
Last edited by Thonex; 11-03-2018 at 08:15 AM.
|
|
|
11-03-2018, 04:13 PM
|
#10
|
Human being with feelings
Join Date: Aug 2012
Posts: 271
|
I think it will be the best option. Take a piece of code from here.
This is a comparison of two envelopes (fast-slow) with a small nuance.
https://forum.cockos.com/showthread.php?t=182188
|
|
|
11-03-2018, 04:33 PM
|
#11
|
Human being with feelings
Join Date: Dec 2012
Posts: 7,294
|
Quote:
Originally Posted by eugen2777
|
I keep forgetting to download that thing!
|
|
|
11-04-2018, 03:23 PM
|
#12
|
Human being with feelings
Join Date: May 2018
Location: Los Angeles
Posts: 1,721
|
OK.... So I think I got what I wanted. I'm sharing the code below in case it might help someone. The algo has 2 basic parts:
1) look for drastic changes in slope
2) make sure the drastic changes in slope are also accompanied by drastic changes in sample value.
This works for my highly specialized purpose of finding discontinuous audio waveform clicks with tonal instruments. In my case there was always a click across both L/R channels on stereo channels so I only looked at the first channel on stereo... so it would go twice as fast. I tried to use local variables where I though it mades sense... if someone can clue me into where else I would need local vars to speed up the algo... please comment.
Here I analyzed 4 files, stereo and mono, knowing that there were clicks near the top of the test files. The script put markers where the candidates were (no false positives on these tests). I zoom in so you can see the click waveform, and then tab through the markers:
Shift-Ctrl-T to run script. and "]" to tab to the next markers.
Code:
--[[
Description: Put a marker inndex 0 at click suspects
Version: 1.0.0
Author: Thonex
]]--
function Msg (param)
reaper.ShowConsoleMsg(tostring (param).."\n")
end
function DETECT_CLICK ()
local ii = 1
while ii < Samples_Per_Item-Num_Channels*2 do
-------- De-Click Algo ---------
if S_Buffer[ii+Num_Channels] >= S_Buffer[ii] then -- look at first Slope
Slope1 = math.abs(S_Buffer[ii]-S_Buffer[ii+Num_Channels])
else
Slope1 = math.abs(S_Buffer[ii]-S_Buffer[ii+Num_Channels]) * -1
end
if S_Buffer[ii+Num_Channels*2] >= S_Buffer[ii+Num_Channels] then -- look at next Slope
Slope2 = math.abs(S_Buffer[ii+Num_Channels]-S_Buffer[ii+Num_Channels*2])
else
Slope2 = math.abs(S_Buffer[ii+Num_Channels]-S_Buffer[ii+Num_Channels*2]) * -1
end
if Slope2 ~= 0 then -- calciulate % ∆ Slope and ignore if divisor is zero
Delta_Slope = Slope2/Slope1
end
if ((Slope1 >= 0 and Slope2 < 0) -- if Slopes are opposite sign
or (Slope1 <= 0 and Slope2 >0)) -- if Slopes are opposite sign
and (math.abs(Slope1) > Slope_Threshold or math.abs(Slope2) > Slope_Threshold) then
reaper.AddProjectMarker( 0, 0, position+((1/srate)*(ii/Num_Channels)), 0, "Click", 0 )
end
-- Msg(S_Buffer[ii].. " ".. S_Buffer[ii+Num_Channels].. " Dif: ".. Slope1 .. " ".. Delta_Slope)
-- Msg(Slope1 .." ".. Slope2 .. " Delta_Slope= ".. Delta_Slope)
-- Msg(S_Buffer[ii])
ii=ii+Num_Channels
end
end
function TEST()
reaper.ClearConsole()
--reaper.DeleteProjectMarkerByIndex( 0,0 )
items = reaper.CountSelectedMediaItems(0)
Slope_Threshold = .03 -- difference in Slopes from one sample segement to next
for i=0,items-1 do
item = reaper.GetSelectedMediaItem(0, i)
take = reaper.GetActiveTake(item)
source = reaper.GetMediaItemTake_Source(take)
position = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
length = reaper.GetMediaItemInfo_Value(item, "D_LENGTH")
srate = reaper.GetMediaSourceSampleRate(source)
Num_Channels = tonumber(reaper.GetMediaSourceNumChannels(source))
reaper.SetMediaItemTakeInfo_Value(take, "I_CHANMODE", 0)
Samples_Per_Ch = math.floor(length*srate)
Samples_Per_Item = math.floor(Samples_Per_Ch*Num_Channels)
Accessor = reaper.CreateTakeAudioAccessor(take)
S_Buffer = reaper.new_array(Samples_Per_Item)
reaper.GetAudioAccessorSamples(Accessor, srate, Num_Channels, 0, Samples_Per_Ch, S_Buffer)
reaper.DestroyAudioAccessor(Accessor)
DETECT_CLICK ()
end
--[[
Msg(Num_Channels)
Msg(chanmode)
Msg(srate)
Msg(length)
Msg("Samples Per Channel: ".. Samples_Per_Ch)
Msg("Number for samples Total: ".. Samples_Per_Item)
--]]
reaper.UpdateArrange()
end
TEST()
__________________
Cheers... Andrew K
Reaper v6.80+dev0621 - June 21 2023 • Catalina • Mac Mini 2020 6 core i7 • 64GB RAM • OS: Catalina • 4K monitor • RME RayDAT card with Sync Card and extended Light Pipe.
Last edited by Thonex; 11-04-2018 at 10:38 PM.
|
|
|
11-04-2018, 07:33 PM
|
#13
|
Human being with feelings
Join Date: May 2017
Posts: 3,204
|
Quote:
Originally Posted by ashcat_lt
Honestly I think what you want to look for is sudden large changes in the slope. Take a look at the JS trainsient plug (or my Transient Splitter which should be in the stash). It keeps two running averages - one shorter than the other. When the difference (or ratio? I'd have to look again) between those two envelopes is significantly different, it counts as a transient. That's about exactly what you want, I think.
|
That's what I immediately thought - monitor not just the slope, but also the slope of the slope; the double derivative of the samples in time.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 03:26 PM.
|