Log in

View Full Version : Removing regular audio dropouts?


kuchikirukia
3rd August 2019, 20:48
I have an audio file that has dropouts every 1000ms. These dropouts increase in duration as follows:

0ms (no gap)
4ms
6ms
8
11
14
16
19

and then back to 0

(there may be slight variations in the gap length between cycles, on the order of 1ms, but I'm not worried about that being audible)

Is there a way to programmatically cut these out? If not with avisynth, is there another tool?

The audio is over 3 hours long so doing it manually would take a while.

Doorn9
3rd August 2019, 22:23
I think your best bet is Audacity (a free audio editor). When you select the entire track, there is an option to 'truncate silence'. Haven't tried it, but that should be about right - unless there's other silences that you need to retain. If so, you'd have to go through it parts at the time.

Good luck!

johnmeyer
4th August 2019, 05:50
I have the (expensive) iZotope RX which has a "spectral repair" tool that is specifically designed to fix small audio gaps by interpolating from surrounding sound. It is not automatic, but it sure works well. You could download the trial and see if it can do what you want.

kuchikirukia
4th August 2019, 07:32
Unfortunately that doesn't work very well since it isn't necessarily complete silence, and there's good sections which have levels down at the level of the little blips of noise.
Going through 3 hours of audio multiple times to fix what it gets wrong would take me longer than deleting manually one second at a time.

I have the (expensive) iZotope RX which has a "spectral repair" tool that is specifically designed to fix small audio gaps by interpolating from surrounding sound. It is not automatic, but it sure works well. You could download the trial and see if it can do what you want.

It doesn't look like it needs interpolation. The audio doesn't look like it's missing, it looks like it was stretched with silence. Deleting the gaps sounds fine to my ears. There's just 12,960 of them to delete.

tebasuna51
4th August 2019, 10:54
I don't know if I understand your problem. But ...

WavSource("input.wav")
AudioDubEx(BlankClip(length=Int(1000*AudioLengthF(last)/Audiorate(last)), width=32, height=32, pixel_type="RGB24", fps=1000), last)

Now you have a clip with a frame each ms (fps 1000).
And now you can use Timeline editing filters like Trim or SelectEvery to select the desired part.

kuchikirukia
4th August 2019, 11:59
How would I do that since the values change?

It's a cycle of 8000 frames out of which I want to cut frames 1000-1003, 2000-2005, 3000-3007, 4000-4010, 5000-5013, 6000-6015, and 7000-7018.

Is it going to have to be in steps? Like
Selectrangeevery(8000,7996,1000)
then
Selectrangeevery(7996,7994,1996)
since we've cut 4 frames

Is there an audio graph for avisynth so I could look at what the audio is doing frame by frame?

StainlessS
4th August 2019, 12:20
Take a look at Wonkey_Donkey WaveForm:- https://forum.doom9.org/showthread.php?t=165703&highlight=Waveform

From last post in that thread.
https://i.postimg.cc/26N4fw7f/Wave-Form-Film-Strip-00.jpg (https://postimages.org/)

Is it "Digital Silence", ie multiple values of exactly 0 ?

EDIT: You might have to do something like AssumeFPS(1000.0) beforehand to see something useful. [@ eg 48KHz, then 48 samples per frame (of course frame numbers will be off/wrong)]


Colorbars
Assumefps(1000.0)

WINDOW = 1 # Frames Wide = 2 * WINDOW + 1
HEIGHT = 1.0 # Audio graphs height, 0.333 = 1/3 of result filmstrip image height.
UNDER = True # True, then audio graphs stacked under video, else overlay over video.
ZOOM = 1.0 # Amplify audio signal for viewing (1.0=No Amp).
SUBSIZE = 0.2 # Suggest 0.0(off) to about 0.5. (0.0 <= SubSize <= 1.0) : 0.0 = No Frame Number, 1.0=biggest size for current clip Height (probably too big).
SHOWAUDIO = True # Default True. If False, Switches OFF WaveForm Display, Shows FilmStrip Only.
W = 264 # Default -1, (or 0 or +ve). -1 = Normal Downscale behaviour, filmstrip width ~= input clip width.
#H = Undefined # Undefined, Let W govern height of thumbnail images (or just dont use h=H in function call, same as h=Undefined).

WaveForm_FilmStrip(window=WINDOW,Height=HEIGHT,under=UNDER,zoom=ZOOM,subSize=SUBSIZE,ShowAudio=SHOWAUDIO,w=W) #,h=H)


https://i.postimg.cc/wMr7cGKJ/z-00.jpg (https://postimages.org/)
Upper channel above is digital silence.


Colorbars
Assumefps(1000.0)

WINDOW = 1 # Frames Wide = 2 * WINDOW + 1
HEIGHT = 1.0 # Audio graphs height, 0.333 = 1/3 of result filmstrip image height.
UNDER = True # True, then audio graphs stacked under video, else overlay over video.
ZOOM = 1.0 # Amplify audio signal for viewing (1.0=No Amp).
SUBSIZE = 0.2 # Suggest 0.0(off) to about 0.5. (0.0 <= SubSize <= 1.0) : 0.0 = No Frame Number, 1.0=biggest size for current clip Height (probably too big).
SHOWAUDIO = True # Default True. If False, Switches OFF WaveForm Display, Shows FilmStrip Only.
W = 480 # Default -1, (or 0 or +ve). -1 = Normal Downscale behaviour, filmstrip width ~= input clip width.
#H = Undefined # Undefined, Let W govern height of thumbnail images (or just dont use h=H in function call, same as h=Undefined).

WaveForm_FilmStrip(window=WINDOW,Height=HEIGHT,under=UNDER,zoom=ZOOM,subSize=SUBSIZE,ShowAudio=SHOWAUDIO,w=W) #,h=H)

https://i.postimg.cc/8zYdZZG1/z-01.jpg (https://postimg.cc/PCm8xzNc)e85 gas station los angeles (https://gasstation-nearme.com/e85)

kuchikirukia
4th August 2019, 12:37
I got audiograph working.

Now I don't know any way to trim this without 12,900 individual trim commands, which would take longer to type than to just delete them manually.

e: ok, let's see if something like this works...

https://i.postimg.cc/kGQpWkRY/Untitled.png

e2: doesn't work. "Argument list too long"

So how am I going to do trim(0,1000)++trim(1003,2000)++trim(2005,3000)++trim(3007,4000)++trim(4010,5000)++trim(5013,6000)++trim(6015,7000)++trim(7018,8000) and get it to repeat?

e3: ok, so trim doesn't trim the audio so even that doesn't work.

e3, ok, baby steps.
selectrangeevery(8000,7996,980) got rid of the 4ms gap every 8000ms.

So now we do the 6ms, so we should be 4 frames cut every 8k so it should be a new cycle of 7996 frames.

StainlessS
4th August 2019, 13:37
If you can produce a file of either frames to delete, or frames to keep, then can use one of below functions, requires both FrameSel and Prune plugins.


Function RejectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS") {
# RejectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to delete frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here. Prune also does not have a 'reject' arg to delete specified frames rather than select them,
# this wrapper also converts a list of frames to delete into a list of frames to select so that we can use Prune and its audio
# capability.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments also allowed, see FrameSel for Further info).
# TrimAudio:
# True(default), deletes audio belonging to deleted frames
# False, returns original audio, probably out of sync.
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,reject=true)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,reject=true,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}

Function SelectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS",Bool "Ordered") {
# SelectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to Select frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments allowed, see FrameSel for Further info).
# *** NOTE ***, If both Cmd and SCmd supplied AND Ordered == False, then will process Cmd file and then SCmd string afterwards, ie
# Will select ranges in Cmd file and in order specified (rather than auto ordering ranges) and then append ranges specified in
# SCmd string (and in order specified).
# TrimAudio:
# True(default), selects audio belonging to selected frames/ranges
# False, returns original audio, probably out of sync (maybe totally out of whack if Ordered == false and selected ranges out of order).
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
# Ordered:
# True(default), all frames/ranges are returned in sequencial order. Any frame specified more than once will return only 1 instance.
# False, All frames/Ranges are returned in specified order, Cmd processed first and then SCmd. Frames/ranges specified more than once
# will return multiple instances. Allows out-of-order trimming of clip, eg re-sequencing of scenes in movie.
#
# Does not make much sense to select individual frames with audio, best used with ranges.
# Will coalesce individually selected adjacent frames/ranges before any Fade, ie only audio fade where sensible to do so.
# TrimAudio==false with non Ordered selection will result in completely out of sync audio.
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
Ordered=Default(Ordered,True) # True (default) frames/ranges will be Ordered and selected only once even if specified more than once.
# False, frames/ranges returned in specified order, Cmd processed 1st and then SCmd.
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,Ordered=Ordered)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,Ordered=Ordered,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}


You would MAYBE call with FadeMS=0.0[OFF] (but might be better with default 1.0).

Rough code to produce Frames file, you choose, either frames to keep or frames to reject.
Below untested in any way, writes single frames, but easily converted to ranges, if you pick a method to choose frames/range.

FN=".\Frames.txt"
FN=RT_GetFullPathName(FN)
RT_FileDelete(FN)

Avisource(...)
Assumefps(1000.0) # EDIT: Actually use your BlankClip code
FC = FrameCount
M = (FC-1) / 1000

For(i=0,M) {
n = i * 1000 # multiple of 1000 frame number
For(j=0,999) {
f = n + j # frame number
if(f < FC) { # do process existing frames

Process= ??? # Frame to Process
(Process) {
RT_WriteFile(FN, "%d",f,Append=True) # To Write Ranges, eg: RT_WriteFile(FN, "%d %d",S,E,Append=True)
}

} Else {
j = 999 # Break, all done
i = M # Ditto
}
}
}

return MessageClip("DONE")


Rubbish in RED.
EDIT: If you choose RejectRanges method (which would seem the easier way),
then can use FrameSel(Reject=False) together with the same Frames file, to extract the deleted frame/audio, so that you can see what is/was deleted.
And if you choose the SelectRanges method, then can use FrameSel(Reject=True), to do the same thing and view deleted frames/audio.
EDIT: Ignore above, forgot that FrameSel only returns VIDEO frames, NOT AUDIO.
BUT, Can use the alternate ranges function to view Video/Audio that was deleted.
Ie, if using RejectRanges() method then use SelectRanges() with same frames file to view deleted audio,
if using SelectRanges() method, then use RejectRanges() to view deleted audio.

kuchikirukia
4th August 2019, 14:53
Ugh, why does my manually done section sound perfect but it sounds terrible when I do it with selectrangeevery?

StainlessS
4th August 2019, 15:01
Show us some of your Frames file, and did you try both FadeMS=0.0 and default FadeMs=1.0

Assuming you chose RejecRanges() method, then also take a peek at SelectRanges() with same Frames file, and with FadeMS=0.0.
It will show deleted frames/audio.

EDIT: Also show us an image of typical problem using WaveForm_FilmStrip(preferable with wide enough range to show full extent) or audiograph.

EDIT: And check your numbers, ie 0->1000 is 1001 frames, and 0->8000, is 8001 frames.
When you;ve checked and corrected your numbers then say again what it should be.

StainlessS
4th August 2019, 16:08
OK, this easier for you to make same as your hand edits.

Untested

# ... # Your source to 1000 FPS

# Using Global to check for USER errors, and for short function call.
Global FN=RT_GetFullPathName(".\Frames.txt")
Global CHUNK_SZ = 8000
Global FC = FrameCount
Global CHKMX = (FC-1) / CHUNK_SZ

RT_FileDelete(FN)

# Your frames (not well spec'ed, should spec in range eg 0->999, not 0->1000, otherwise next group dont start at 1000, but at 1001, same for 0->8000, should be 0->7999).
# trim(0,1000)++trim(1003,2000)++trim(2005,3000)++trim(3007,4000)++trim(4010,5000)++trim(5013,6000)++trim(6015,7000)++trim(7018,8000) and get it to repeat?

For(i=0,CHKMX) { # repeated every 8000 When CHUNK_SZ = 8000
Global Chunk_Num = i
### List of frames to Delete in every chunk of CHUNK_SZ frames, may be in range 0 -> CHUNK_SZ-1
# trim(0,1000)
# Nothing to do
# trim(1003,2000)
DF(1001)
DF(1002)
# trim(2005,3000)
DF(2001)
DF(2002)
DF(2003)
DF(2004)
# trim(3007,4000)
DF(3001)
DF(3002)
DF(3003)
DF(3004)
DF(3005)
DF(3006)
# trim(4010,5000)
DF(4001)
DF(4002)
DF(4003)
DF(4004)
DF(4005)
DF(4006)
DF(4007)
DF(4008)
DF(4009)
# trim(5013,6000)
DF(5001)
DF(5002)
DF(5003)
DF(5004)
DF(5005)
DF(5006)
DF(5007)
DF(5008)
DF(5009)
DF(5010)
DF(5011)
DF(5012)
# trim(6015,7000)
DF(6001)
DF(6002)
DF(6003)
DF(6004)
DF(6005)
DF(6006)
DF(6007)
DF(6008)
DF(6009)
DF(6010)
DF(6011)
DF(6012)
DF(6013)
DF(6014)
# trim(7018,8000) # bad spec 8000, is in next chunk [unless CHUNK_SZ should be 8001 frames)
DF(7001)
DF(7002)
DF(7003)
DF(7004)
DF(7005)
DF(7006)
DF(7007)
DF(7008)
DF(7009)
DF(7010)
DF(7011)
DF(7012)
DF(7013)
DF(7014)
DF(7015)
DF(7016)
DF(7017)
}

return Messageclip("Done")

Function DF(Int Chunk_ix) { # delete chunk ix frame
myName="DF: "
Assert(Chunk_ix < CHUNK_SZ,RT_string("%sInvalid Chunk_Ix(%d) Max allowed CHUNK_SZ-1(%d)",myName,Chunk_ix,CHUNK_SZ))
Assert(Chunk_num <= CHKMX,RT_string("%sInvalid Chunk_Num(%d) Max allowed CHKMX(%d)",myName,Chunk_num,CHKMX)) # EDIT: Changed < to <=
ChunkBase = Chunk_num * CHUNK_SZ # Multiple of CHUNK_SZ eg 0, 8000, 16000, 24000, 32000, etc
n = ChunkBase + Chunk_ix # Frame number
if(n < FC) {
RT_WriteFile(FN, "%d",n,Append=True)
}
}

kuchikirukia
4th August 2019, 16:19
This is what it looks like:
https://i.postimg.cc/dQbh6bd5/Untitled.png

Is selectrangeevery(8000,7996) 8000 frames? It looks like it.

I'm going like 10% into the thing and it looks like I'm still cutting in exactly the right spot but it sounds like crap, when my eyeballed mouse selections in audacity sound great.

New plan: I'm going to leave one frame of silence on each side and just close the big gap in the middle, just to make sure I'm not cutting off too much.
There's be one less step to this if MeGUI could output in WAV.

Edit2: Well that failed. New new plan -- get values from Audacity.

StainlessS
4th August 2019, 16:24
Prev script should be exactly like your bad spec'ed trim list.
can you upload audio sample somewhere,

kuchikirukia
4th August 2019, 17:17
File:

https://www.filehosting.org/file/details/814794/190719%20Bilibili%20Macro%20Link%20VR.mka

The skips shift at 1:57:52. Still look to be 1000ms apart, they just don't align with the first part.

StainlessS
5th August 2019, 17:19
OK, got the audio clip.
I used this

FN=RT_GetFullPathName(".\190719 Bilibili Macro Link VR.mka")
FFAudioSource(FN)
V=BlankClip(Length=Int(1000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=1000,last)
AudioDub(V,Last)

ZOOM=4.0 # Will clip peaks, but easier to see

WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)

return last


but I'm seeing different silent frames to you.
How did you convert mka to WAV, so I can see same as you ? [ffmpeg ?]

these are first few silences that I'm seeing

520, 532
1520,1534
2520,2538

EDIT: Well maybe start at 519
https://i.postimg.cc/HnHSZXL3/k-00.jpg (https://postimg.cc/WFW6tDgJ)


EDIT: Maybe this is you best bet [ffmpeg]
Google "ffmpeg trim silence audio" :- https://www.google.co.uk/search?q=ffmpeg+trim+silence+audio&spell=1&sa=X&ved=0ahUKEwi2wrjKlezjAhVTa8AKHW-kBEMQBQgsKAA&biw=1920&bih=920

StainlessS
5th August 2019, 17:52
I tried using this



ffmpeg -i 1.mka -af silenceremove=10-50dB output.wav

pause

No idea if it worked ok, will probably have to screw around with the db (decibels thingy) for best result.

from Here (StackOverflow):- https://stackoverflow.com/questions/25697596/using-ffmpeg-with-silencedetect-to-remove-audio-silence

EDIT: Above stuff did not seem to do anything, will need mod to "silenceremove=10-50dB" part, presumably.

Oops, should have used
ffmpeg -i 1.mka -af silenceremove=1:0:-50dB output.wav
I'll try again

EDIT:
Nope, still no difference, still 3:36:29.56 length

richardpl
5th August 2019, 18:34
I tried using this



ffmpeg -i 1.mka -af silenceremove=10-50dB output.wav

pause

No idea if it worked ok, will probably have to screw around with the db (decibels thingy) for best result.

from Here (StackOverflow):- https://stackoverflow.com/questions/25697596/using-ffmpeg-with-silencedetect-to-remove-audio-silence

EDIT: Above stuff did not seem to do anything, will need mod to "silenceremove=10-50dB" part, presumably.

Oops, should have used
ffmpeg -i 1.mka -af silenceremove=1:0:-50dB output.wav
I'll try again

EDIT:
Nope, still no difference, still 3:36:29.56 length

That is command for removing silence from begin only.
Please consult fine documentation here: http://ffmpeg.org/ffmpeg-filters.html#silenceremove

Make sure to not use RMS detection and to use shortest window possible.

richardpl
5th August 2019, 19:07
I experimented until 1:30 mark with this settings:

silenceremove=stop_periods=-1:stop_duration=0.000083333:detection=peak:window=0:stop_threshold=-40dB

StainlessS
5th August 2019, 19:43
I experimented until 1:30 mark with this settings:

silenceremove=stop_periods=-1:stop_duration=0.000083333:detection=peak:window=0:stop_threshold=-40dB

I did the entire audio clip with above, [3.5 hours of audio, and took some time [bout 20 mins].

Result was about 30 mins shorter than original. so is chopping out too much. Given the script from post #12 [delete x number of frames for every 8000], from FrameFile generated, we require in the region of 104 seconds of silence removed.

[103905 video frames at 1000FPS]

FFMPeg produces warning with above command
[output stream #0:0 @ 030ebba0] 100 buffers queued in output stream 0:0, something may be wrong.

EDIT:

3:36:29.56 Original length
3:35:45.56 Roughly required
3:06:00.00 silenceremove=stop_periods=-1:stop_duration=0.000083333:detection=peak:window=0:stop_threshold=-40dB [Approximate time, not doing it again for exact timing]
3:27:50.85 ffmpeg -i 1.mka -af silenceremove=stop_periods=-1:stop_duration=0.0083333:detection=peak:window=0:stop_threshold=-40dB output.wav

StainlessS
6th August 2019, 01:28
Could not get anything particularly good with FfMPeg [mostly would not work at all, but then I could not really figure out the cryptic docs).

I went back to script solution.
You must have trimmed the audio you were using as numbers were way off what came out of the source mka.
Just so we are using the same wav file.
I used this to convert.

First rename file to 1.mka, then
#ConvertToWav.cmd

setlocal

REM Where to Find ffmpeg
set FFMPEG="C:\BIN\ffmpeg.exe"

REM Where to get input file, No terminating Backslash, "." = current directory
set INDIR="."


REM Where to place output file, No terminating Backslash.
set OUTDIR="."


FOR %%A IN (*.m4a *.wmv *.mpg *.avi *.flv *.mov *.mp4 *.m4v *.RAM *.RM *.mka) DO (
%FFMPEG% -i "%INDIR%\%%A" -vn -acodec pcm_s16le "%OUTDIR%\%%~nxA.WAV"

)
Pause


MakeFrames.avs # make frames file.

FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(1000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=1000,last)
AudioDub(V,Last)

ZOOM=4.0 # Will clip peaks, but easier to see

WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)

return last # Show WaveForm_FilmStrip # COMMENT OUT to make the FRAMES file.

# Using Global to check for errors, and for short function call.
Global DEBUG=true # write deleted frame numbers to DebugView
Global FRAMES=RT_GetFullPathName(".\Frames.txt")
Global CHUNK_SZ = 8000
Global FC = FrameCount
Global CHKMX = (FC-1) / CHUNK_SZ

RT_FileDelete(FRAMES)

# Your frames (not well spec'ed, should spec in range eg 0->999, not 0->1000, otherwise next group dont start at 1000, but at 1001, same for 0->8000).
# trim(0,1000)++trim(1003,2000)++trim(2005,3000)++trim(3007,4000)++trim(4010,5000)++trim(5013,6000)++trim(6015,7000)++trim(7018,8000) and get it to repeat?

For(i=0,CHKMX) { # repeated every 8000 When CHUNK_SZ = 8000
Global Chunk_Num = i
### List of frames to Delete in every chunk of CHUNK_SZ frames, may be in range 0 -> CHUNK_SZ-1
DF(519, 532)
DF(1519,1535)
DF(2519,2538)
DF(3519)
DF(4519,4522)
DF(5519,5524)
DF(6519,6527)
DF(7519,7529)
}

return Messageclip("Done")

Function DF(Int Chunk_S,Int "Chunk_e") {
myName="DF: "
Chunk_e=Default(Chunk_e,Chunk_s) # Default single frame
Assert(Chunk_s < CHUNK_SZ,RT_string("%sInvalid Chunk_S(%d) Max allowed CHUNK_SZ-1(%d)",myName,Chunk_s,CHUNK_SZ))
Assert(Chunk_e < CHUNK_SZ,RT_string("%sInvalid Chunk_E(%d) Max allowed CHUNK_SZ-1(%d)",myName,Chunk_e,CHUNK_SZ))
Assert(Chunk_s <= Chunk_e,RT_string("%sChunk_s(%d) <= Chunk_e(%d)",myName,Chunk_s,Chunk_e))
Assert(Chunk_num <= CHKMX,RT_string("%sInvalid Chunk_Num(%d) Max allowed CHKMX(%d)",myName,Chunk_num,CHKMX))
ChunkBase = Chunk_num * CHUNK_SZ # Multiple of CHUNK_SZ eg 0, 8000, 16000, 24000, 32000, etc
Chunk_s = ChunkBase + Chunk_s
Chunk_e = ChunkBase + Chunk_e
if(chunk_s < FC) {
Chunk_e = min(Chunk_e,FC-1)
if(Chunk_s==Chunk_e) { # single frame
(DEBUG) ? RT_DebugF("DEL %d",Chunk_s) : NOP
RT_WriteFile(FRAMES, "%d",Chunk_s,Append=True)
} else { # Range
(DEBUG) ? RT_DebugF("DEL %d,%d",Chunk_s,Chunk_e) : NOP
RT_WriteFile(FRAMES, "%d,%d",Chunk_s,Chunk_e,Append=True)
}
}

}


DoTrim.avs # Actually trim and show waveform of result.

Function RejectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS") {
# RejectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to delete frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here. Prune also does not have a 'reject' arg to delete specified frames rather than select them,
# this wrapper also converts a list of frames to delete into a list of frames to select so that we can use Prune and its audio
# capability.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments also allowed, see FrameSel for Further info).
# TrimAudio:
# True(default), deletes audio belonging to deleted frames
# False, returns original audio, probably out of sync.
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,reject=true)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,reject=true,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}


# TRIM OUT bad frames

FRAMES=RT_GetFullPathName(".\Frames.txt")
FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(1000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=1000,last)
V.AudioDub(Last)

FADEMS=0.0 # 0.0 = NO FADE, (default 1.0 = 1ms linear fade)
RejectRanges(Cmd=FRAMES,FadeMS=FADEMS) # TrIm AUDIO

ZOOM=4.0 # Will clip peaks, but easier to see
WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)


ShowRemoved.avs # show frames that were TRIMMED OUT ie removed

Function SelectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS",Bool "Ordered") {
# SelectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to Select frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments allowed, see FrameSel for Further info).
# *** NOTE ***, If both Cmd and SCmd supplied AND Ordered == False, then will process Cmd file and then SCmd string afterwards, ie
# Will select ranges in Cmd file and in order specified (rather than auto ordering ranges) and then append ranges specified in
# SCmd string (and in order specified).
# TrimAudio:
# True(default), selects audio belonging to selected frames/ranges
# False, returns original audio, probably out of sync (maybe totally out of whack if Ordered == false and selected ranges out of order).
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
# Ordered:
# True(default), all frames/ranges are returned in sequencial order. Any frame specified more than once will return only 1 instance.
# False, All frames/Ranges are returned in specified order, Cmd processed first and then SCmd. Frames/ranges specified more than once
# will return multiple instances. Allows out-of-order trimming of clip, eg re-sequencing of scenes in movie.
#
# Does not make much sense to select individual frames with audio, best used with ranges.
# Will coalesce individually selected adjacent frames/ranges before any Fade, ie only audio fade where sensible to do so.
# TrimAudio==false with non Ordered selection will result in completely out of sync audio.
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
Ordered=Default(Ordered,True) # True (default) frames/ranges will be Ordered and selected only once even if specified more than once.
# False, frames/ranges returned in specified order, Cmd processed 1st and then SCmd.
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,Ordered=Ordered)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,Ordered=Ordered,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}


# SHOW TRIMMED OUT bad frames ONLY

FRAMES=RT_GetFullPathName(".\Frames.txt")
FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(1000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=1000,last)
V.AudioDub(Last)

# ShowFrameNumber # EDIT: Show pre trim frame number on frame

FADEMS=0.0 # 0.0 = NO FADE, (defailt 1.0 = 1ms linear fade)
SelectRanges(Cmd=FRAMES,FadeMS=FADEMS) # TrIm AUDIO

ZOOM=4.0 # Will clip peaks, but easier to see
WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)


Its not perfect by any means.

Perhaps FPS=10000 would work better. [and Global CHUNK_SZ = 80000]. Some frames are eg half silence, and half not.
EDIT: Or FPS=4000, Global CHUNK_SZ = 32000

StainlessS
6th August 2019, 03:53
Here with FPS upped to 4000, and CHUNKSZ=32000
I'm kinda surprised a bit that it works OK with 52,000,000 video frames.


# MakeFrames.avs

FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(4000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=4000,last)
AudioDub(V,Last)

ZOOM=4.0 # Will clip peaks, but easier to see

WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)

return last # Show WaveForm_FilmStrip # COMMENT OUT to make the FRAMES file.

# Using Global to check for errors, and for short function call.
Global DEBUG=true # write deleted frame numbers to DebugView
Global FRAMES=RT_GetFullPathName(".\Frames.txt")
Global CHUNK_SZ = 32000
Global FC = FrameCount
Global CHKMX = (FC-1) / CHUNK_SZ

RT_FileDelete(FRAMES)

For(i=0,CHKMX) { # repeated every 8000 When CHUNK_SZ = 8000
Global Chunk_Num = i
### List of frames to Delete in every chunk of CHUNK_SZ frames, may be in range 0 -> CHUNK_SZ-1
DF( 2077, 2130)
DF( 6079, 6136)
DF(10080,10151)
DF(14077)
DF(18077,18089)
DF(22076,22100)
DF(26075,26110)
DF(30076,30121)
}

return Messageclip("Done")

Function DF(Int Chunk_S,Int "Chunk_e") {
myName="DF: "
Chunk_e=Default(Chunk_e,Chunk_s) # Default single frame
Assert(Chunk_s < CHUNK_SZ,RT_string("%sInvalid Chunk_S(%d) Max allowed CHUNK_SZ-1(%d)",myName,Chunk_s,CHUNK_SZ))
Assert(Chunk_e < CHUNK_SZ,RT_string("%sInvalid Chunk_E(%d) Max allowed CHUNK_SZ-1(%d)",myName,Chunk_e,CHUNK_SZ))
Assert(Chunk_s <= Chunk_e,RT_string("%sChunk_s(%d) <= Chunk_e(%d)",myName,Chunk_s,Chunk_e))
Assert(Chunk_num <= CHKMX,RT_string("%sInvalid Chunk_Num(%d) Max allowed CHKMX(%d)",myName,Chunk_num,CHKMX))
ChunkBase = Chunk_num * CHUNK_SZ # Multiple of CHUNK_SZ eg 0, 8000, 16000, 24000, 32000, etc
Chunk_s = ChunkBase + Chunk_s
Chunk_e = ChunkBase + Chunk_e
if(chunk_s < FC) {
Chunk_e = min(Chunk_e,FC-1)
if(Chunk_s==Chunk_e) { # single frame
(DEBUG) ? RT_DebugF("DEL %d",Chunk_s) : NOP
RT_WriteFile(FRAMES, "%d",Chunk_s,Append=True)
} else { # Range
(DEBUG) ? RT_DebugF("DEL %d,%d",Chunk_s,Chunk_e) : NOP
RT_WriteFile(FRAMES, "%d,%d",Chunk_s,Chunk_e,Append=True)
}
}

}



# Dotrim.avs

Function RejectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS") {
# RejectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to delete frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here. Prune also does not have a 'reject' arg to delete specified frames rather than select them,
# this wrapper also converts a list of frames to delete into a list of frames to select so that we can use Prune and its audio
# capability.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments also allowed, see FrameSel for Further info).
# TrimAudio:
# True(default), deletes audio belonging to deleted frames
# False, returns original audio, probably out of sync.
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,reject=true)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,reject=true,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}


# TRIM OUT bad frames

FRAMES=RT_GetFullPathName(".\Frames.txt")
FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(4000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=4000,last)
V.AudioDub(Last)

FADEMS=0.0 # 0.0 = NO FADE, (defailt 1.0 = 1ms linear fade)
RejectRanges(Cmd=FRAMES,FadeMS=FADEMS) # TrIm AUDIO

ZOOM=4.0 # Will clip peaks, but easier to see
WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)



# ShowRemoved.avs

Function SelectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS",Bool "Ordered") {
# SelectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
# Wrapper to Select frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
# The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
# eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
# are only using a single clip here.
#
# SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
# Cmd: Frames/Ranges specified in file (one frame/range per line, comments allowed, see FrameSel for Further info).
# *** NOTE ***, If both Cmd and SCmd supplied AND Ordered == False, then will process Cmd file and then SCmd string afterwards, ie
# Will select ranges in Cmd file and in order specified (rather than auto ordering ranges) and then append ranges specified in
# SCmd string (and in order specified).
# TrimAudio:
# True(default), selects audio belonging to selected frames/ranges
# False, returns original audio, probably out of sync (maybe totally out of whack if Ordered == false and selected ranges out of order).
# FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
# Ordered:
# True(default), all frames/ranges are returned in sequencial order. Any frame specified more than once will return only 1 instance.
# False, All frames/Ranges are returned in specified order, Cmd processed first and then SCmd. Frames/ranges specified more than once
# will return multiple instances. Allows out-of-order trimming of clip, eg re-sequencing of scenes in movie.
#
# Does not make much sense to select individual frames with audio, best used with ranges.
# Will coalesce individually selected adjacent frames/ranges before any Fade, ie only audio fade where sensible to do so.
# TrimAudio==false with non Ordered selection will result in completely out of sync audio.
c
TrimAudio=Default(TrimAudio,True) # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
FadeMS=Float(Default(FadeMS,1.0)) # 1 millisecond linear fadeout/fadein at splices
Ordered=Default(Ordered,True) # True (default) frames/ranges will be Ordered and selected only once even if specified more than once.
# False, frames/ranges returned in specified order, Cmd processed 1st and then SCmd.
PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
(!TrimAudio)
\ ? FrameSel(scmd=SCmd,cmd=Cmd,Ordered=Ordered)
\ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,Ordered=Ordered,Prune=True,range=true)
(TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
# If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
(TrimAudio)
\ ? RT_FileDelete(PruneCmd)
\ : (c.HasAudio) ? AudioDub(c) : NOP
Return Last
}


# SHOW TRIMMED OUT bad frames ONLY

FRAMES=RT_GetFullPathName(".\Frames.txt")
FN=RT_GetFullPathName(".\1.mka.wav")
wavSource(FN)
V=BlankClip(Length=Int(4000*AudioLengthF/AudioRate),Width=800,Pixel_Type="RGB24",fps=4000,last)
V.AudioDub(Last)
Global CHUNKSZ=32000

SSS=""" n = current_frame m=n%CHUNKSZ Subtitle(String(n,"%.0f] ") + String(m,"%.0f"),size=32) """
Scriptclip(SSS,After_Frame=True) # Show Original Frame number + frame number mod CHUNKSZ

FADEMS=0.0 # 0.0 = NO FADE, (defailt 1.0 = 1ms linear fade)
SelectRanges(Cmd=FRAMES,FadeMS=FADEMS) # TrIm AUDIO

ZOOM=4.0 # Will clip peaks, but easier to see
WaveForm_FilmStrip(Window=1,Height=1.0,Under=true,Zoom=ZOOM,Marks=true,SubSize=.2,ShowAudio=true,W=640)

Above ShowRemoved shows removed (supposed silent) frames, and also shows original frame number and original frame number modulo CHUNKSZ(32000).
In addition, clearly shows where it goes out of sink. [@ frame 28,290,076 where 4000FPS]

kuchikirukia
10th August 2019, 00:45
I think the Audacity forums may have me covered.

StainlessS
10th August 2019, 14:06
Here is kuchikirukia thread on Audacity forum:- https://forum.audacityteam.org/viewtopic.php?f=69&t=106212

Prev post would have done the same at 0.25 ms resolution instead of 1.0 ms, and in one chunk instead of 10 mins chunks.
However, you would have had to split the file at point where it goes out of sync (which I presume was an audio splice, also presume that there is only one splice in audio,
presume that you also had to do this in Audacity method).
EDIT: At 1000.0 FPS, 1ms skips, you lost some audio, or had silence not chopped out, reason we went to 0.25ms skips and 4000.0 FPS.

EDIT: You would also have had to use the ffmpeg batch file [post #21] to convert to WAV (so that we are both using same wav file, your posted numbers did not correspond to times in
mkv file).

kuchikirukia
10th August 2019, 22:01
I'll try yours since I wasted three hours doing the 10 minute chunks on the lower quality file.

StainlessS
11th August 2019, 00:20
Should be quite quick, the MakeFrames script only takes a couple of seconds on my crap machine [4 or 5 maybe].

Use the ShowRemoved script to check that you are not removing good audio, also check where it goes out of sink about 1/2 -> 2/3 way through the clip.

StainlessS
13th August 2019, 03:55
No good ?