Umamio
30th March 2009, 20:30
A big hurdle for people starting out with avisynth seems to be the difficulty with doing things they expect to be simple, like splicing two clips together from different sources.
Figuring out how to make the clip properties match is a good way to learn about the basics of Avisynth (it's how I learned!) but not everyone has the inclination to do so.
I wrote a function for myself a few months ago to simplify the task of splicing a company intro-video to all the different kinds of videos we receive and I have been thinking of generalising it so that it can be used as a sort of super-splice.
Essentially I want to make a function that takes all the properties of the first clip and applies them to the second clip in as "natural" a way as possible with as little configuration as possible.
Code (Probably full of bugs)
function plus(float x)
{ return (1+float(x)/100) }
function minus(float x)
{ return (1-float(x)/100) }
function AudioMakerST(int channels, clip stereo) {
Assert(channels > 0, "AudioMaker: cannot produce audio with less than 1 channel")
return (channels > 2 \
? MergeChannels(stereo, AudioMakerST(channels - 2, stereo)) \
: (channels == 2 \
? stereo \
: \
stereo.ConvertToMono() \
))
}
function borderBattle(clip l, clip c, float lAR, float cAR, float PARl, int col)
{
wMod = Abs(Round(((l.height*cAR)-(l.Height*lAR))/(2*PARl)))
hMod = Abs(Round(((float(l.width)/cAR)-(float(l.width)/lAR))/2*PARl))
l = l.convertToRGB32
l = (lAR >= cAR) ? l.AddBorders(0,hMod,0,hMod, color=col)
\ : l.AddBorders(wMod,0,wMod,0, color=col)
return l
}
function cropBattle (clip l, clip c, float lAR, float cAR, float PARl)
{
wMod = Abs(Round(((l.height*cAR)-(l.Height*lAR))/(2*PARl)))
hMod = Abs(Round(((float(l.width)/cAR)-(float(l.width)/lAR))/2*PARl))
l = l.convertToRGB32
l = (lAR < cAR) ? l.Crop(0,hMod,0,-hMod)
\ : l.Crop(wMod,0,-wMod,0)
return l
}
function gpSplice(clip c, clip l, float "PARc", float "PARl", float "MaxARError" \
, float "MaxSpeedMod", bool "silence", bool "keepAudioC", bool "keepAudioL" \
, string "customFuncC", string "customFuncL", string "Resampler", int "BGcolour" \
, string "Resizer", int "destW", int "destH", string "Position", int "sRate", int "aChannels"\
, clip "ReplacementAudioTrack", string "mod")
{
PARc = Default(PARc, 1.0)
PARl = Default(PARl, 1.0)
MaxARError = Default(MaxARError, 0)
MaxSpeedMod = Default(MaxSpeedMod, 5.0)
silent = (c.AudioChannels == 0) ? True : False
silence = Default(silence, silent)
keepAudioC = Default(keepAudioC, (!silence))
keepAudioL = Default(keepAudioL, (!silence))
dftRate = c.hasAudio ? c.AudioRate \
: l.hasAudio ? l.audioRate : 48000
sRate = Default(sRate, dftRate)
dftChans = c.hasAudio ? c.AudioChannels \
: l.hasAudio ? l.AudioChannels : 2
aChannels = Default(aChannels, dftChans)
Resizer = Default(Resizer, "Spline36Resize")
Resampler = Default (Resampler, "ResampleAudio")
customFuncC = Default(customFuncC, "none")
customFuncL = Default(customFuncL, "none")
Position = Default(Position, "before")
BGcolour = Default(BGcolour, 000000)
destW = Default(destW, c.width)
destH = Default(destH, c.Height)
ReplacementAudioTrack = Default(ReplacementAudioTrack, BlankClip.killAudio)
#Mod = [ Crop | Pad (AddBorders) ]
mod = Default(mod, "pad")
cAR = float(c.width)/c.height * PARc
lAR = float(l.width)/l.height * PARl
#parC=
#parL=
#Eval User defined func
l = (customFuncL == "none") ? l : Eval ("l."+customFuncL)
c = (customFuncC == "none") ? c : Eval ("c."+customFuncC)
# If replacement audio track exists, kill All Audio
# If l does not have audio but want to keep audio of c, dub silent audio to l
# If l has audio && want to keep c audio but not l audio, replace l audio with silent audio
# All other cases, keep original l audio (or original lack of audio)
l = (!(l.hasAudio) && (KeepAudioC || KeepAudioL)) \
|| ((l.hasAudio) && KeepAudioC && !KeepAudioL) ? \
AudioDub(l.KillAudio,BlankClip(l, audio_rate=sRate, channels=aChannels)) \
: (ReplacementAudioTrack.hasAudio) || (!KeepAudioC && !KeepAudioL) ? l.killAudio\
: l
# If replacement audio track exists, kill audio
# If c does not have audio but want to keep audio of l, dub silent audio to c
# If c has audio && want to keep l audio but not c audio, replace c audio with silent audio
# All other cases, keep original c audio (or lack of audio)
c = ((!(c.hasAudio) && (KeepAudioC || KeepAudioL)) \
|| ((c.hasAudio) && KeepAudioL && !KeepAudioC )) ? \
AudioDub(c.KillAudio,BlankClip(c, audio_rate=sRate, channels=aChannels)) \
: (ReplacementAudioTrack.hasAudio) || (!KeepAudioC && !KeepAudioL) ? c.killAudio\
: c
#Match Audio Channels
##############################################
#Expand this.
l = (c.AudioChannels == l.audioChannels) ? l: \
(c.hasAudio) && (l.AudioChannels==2) ? \
AudioDub(l.killAudio,AudioMakerST(c.AudioChannels, l)) \
: !(c.hasAudio) ? l.killAudio \
: Assert("Need Stereo Audio to use AudioMaker, Hope to fix soon")
##############################################
# Match Framerate
#If framerate difference greater than acceptable; change fps (decimate duplicate),
#else speedup / slowdown to match film.
l = (c.FramerateNumerator == l.FramerateNumerator) && (c.FramerateDenominator == l.FramerateDenominator) ? l \
: (l.Framerate > c.Framerate*(plus(maxSpeedMod)) \
|| (l.Framerate < c.Framerate*(minus(maxSpeedMod))) ? \
l.ChangeFPS(c.FramerateNumerator , c.FramerateDenominator, true) \
: l.AssumeFPS(c.FramerateNumerator , c.FramerateDenominator, true))
# Is AR discrepancy acceptable?
mod = (cAR < lAR*minus(maxARError)) \
|| (cAR > lAR*plus(maxARError)) ? \
mod : "none"
#Crop or Pad to match Source AR
l = (mod == "none") ? l \
: (mod == "pad") ? l.borderBattle(c, lAR,cAr, PARl, BGcolour) \
: (mod=="crop") ? l.cropBattle(c, lAR, cAR, PARl) \
: l
#Match Frame Dimensions
l = Eval ("l."+Resizer+"(destW,destH)")
c = Eval ("c."+Resizer+"(destW,destH)")
#Match Colourspace
l = ( (c.IsYV12) ? ConvertToYV12(l) :
\ (c.IsRGB32) ? ConvertToRGB32(l) :
\ (c.IsRGB24) ? ConvertToRGB24(l) :
\ (c.IsYUY2) ? ConvertToYUY2(l) :
\ (c.IsYUV) ? ConvertToYUV(l) :
\ (c.IsRGB) ? ConvertToRGB(l) : l)
#Match Sample Rate
c = !(c.hasAudio) ? c : Eval ("c."+Resampler+"(sRate)")
l = (!(c.hasAudio) || (c.Audiorate == l.Audiorate)) ? l : Eval ("l."+Resampler+"(sRate)")
#Match AudioBits
l = (!(c.hasAudio) || (c.Audiobits == l.Audiobits)) ? l:
\ (c.Audiobits == 16) ? l.ConvertAudioTo16bit :
\ (c.Audiobits == 24) ?l.ConvertAudioTo24bit :
\ (c.Audiobits == 32) ?l.ConvertAudioTo32bit :
\ (c.Audiobits == 8) ?l.ConvertAudioTo8bit : l
######
##Splice
######
c = (Position == "before") ? l++c \
: (Position == "after") ? c++l \
: (Position == "middle") ? c.Trim(0,c.framecount/2)++l++c.Trim(c.framecount/2+1, c.framecount) \
: l++c
c = (ReplacementAudioTrack.hasAudio) ? Eval ("AudioDubEx(c,ReplacementAudioTrack)."+Resampler+"(sRate)") : c
return c
}
Usage
ClipWithDesirableProperties = ...
OtherClip = ...
ClipWithDesirableProperties.gpSplice(OtherClip)
The main problem I have is with matching audio channels. The way I am doing it now assumes the clip to be modified is originally stereo that can be built up (cheaply) to any number of channels, but I need to find an elegant way to be able to go from any number of channels to any other number of channels.
These functions from tebasuna51 seem promising, but they are all from x channels to stereo. It seems like I will probably have to write one function per channelnumber pair per sourcetype.
Can anyone help? :)
function Dmix3Stereo(clip a) { # 3 Channels L,R,C or L,R,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
return MixAudio(flr, fcc, 0.5858, 0.4142)
}
function Dmix3Dpl(clip a) { # 3 Channels only L,R,S
flr = GetChannel(a, 1, 2)
sl = GetChannel(a, 3)
sr = Amplify(sl, -1.0)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.5858, 0.4142)
}
function Dmix4lStereo(clip a) { # 4 Channels L,R,C + LFE
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lfe = GetChannel(a, 4, 4)
clf = MixAudio(fcc, lfe, 0.2929, 0.2929)
return MixAudio(flr, clf, 0.4142, 1.0)
}
function Dmix4qStereo(clip a) { #4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
blr = GetChannel(a, 3, 4)
return MixAudio(flr, blr, 0.5, 0.5)
}
function Dmix4qDpl(clip a) { # 4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
bl = GetChannel(a, 3)
br = GetChannel(a, 4)
sl = MixAudio(bl, br, 0.2929, 0.2929)
sr = MixAudio(bl, br, -0.2929, -0.2929)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.4142, 1.0)
}
function Dmix4qDpl2(clip a) { # 4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
bl = GetChannel(a, 3)
br = GetChannel(a, 4)
sl = MixAudio(bl, br, 0.3714, 0.2144)
sr = MixAudio(bl, br, -0.2144, -0.3714)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.4142, 1.0)
}
function Dmix4sStereo(clip a) {# 4 Channels L,R,C,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.4142, 0.2929)
blr = GetChannel(a, 4, 4)
return MixAudio(flr, blr, 1.0, 0.2929)
}
function Dmix4sDpl(clip a) { # 4 Channels L,R,C,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.4142, 0.2929)
sl = GetChannel(a, 4)
sr = Amplify(sl, -1.0)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 1.0, 0.2929)
}
function Dmix5Stereo(clip a) { # 5 Channels L,R,C,SL,SR -> Stereo
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3694, 0.2612)
blr = GetChannel(a, 4, 5)
return MixAudio(lrc, blr, 1.0, 0.3694)
}
function Dmix5Dpl(clip a) { # 5 Channels L,R,C,SL,SR -> dpl
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3205, 0.2265)
bl = GetChannel(a, 4)
br = GetChannel(a, 5)
sl = MixAudio(bl, br, 0.2265, 0.2265)
sr = MixAudio(bl, br, -0.2265, -0.2265)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix5Dpl2(clip a) { # 5 Channels L,R,C,SL,SR -> dpl II
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3254, 0.2301)
bl = GetChannel(a, 4)
br = GetChannel(a, 5)
sl = MixAudio(bl, br, 0.2818, 0.1627)
sr = MixAudio(bl, br, -0.1627, -0.2818)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Stereo(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3694, 0.2612)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.3694)
}
function Dmix6Dpl(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3205, 0.2265)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2265, 0.2265)
sr = MixAudio(bl, br, -0.2265, -0.2265)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Dpl2(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3254, 0.2301)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2818, 0.1627)
sr = MixAudio(bl, br, -0.1627, -0.2818)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6StereoLfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3)
lfe = GetChannel(a, 4)
lfc = MixAudio(fcc, lfe, 0.2071, 0.2071)
mix = MergeChannels(lfc, lfc)
lrc = MixAudio(flr, mix, 0.2929, 1.0)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.2929)
}
function Dmix6StereoLfe2(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2929, 0.2071)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.2071)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.2929)
}
function Dmix6DplLfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2613, 0.1847)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.1847)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.1847, 0.1847)
sr = MixAudio(bl, br, -0.1847, -0.1847)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Dpl2Lfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2646, 0.1870)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.1870)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2291, 0.1323)
sr = MixAudio(bl, br, -0.1323, -0.2291)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
return MergeChannels(l, r)
}
Once I've fixed the audio issues I'm thinking of adding an option to pad / border with stretched & blurred edges of the video rather than a flat colour. I've seen it on television occasionally when they're putting 4:3 sources in a 16:9 frame. It generally looks crap, but could be useful for someone!
Figuring out how to make the clip properties match is a good way to learn about the basics of Avisynth (it's how I learned!) but not everyone has the inclination to do so.
I wrote a function for myself a few months ago to simplify the task of splicing a company intro-video to all the different kinds of videos we receive and I have been thinking of generalising it so that it can be used as a sort of super-splice.
Essentially I want to make a function that takes all the properties of the first clip and applies them to the second clip in as "natural" a way as possible with as little configuration as possible.
Code (Probably full of bugs)
function plus(float x)
{ return (1+float(x)/100) }
function minus(float x)
{ return (1-float(x)/100) }
function AudioMakerST(int channels, clip stereo) {
Assert(channels > 0, "AudioMaker: cannot produce audio with less than 1 channel")
return (channels > 2 \
? MergeChannels(stereo, AudioMakerST(channels - 2, stereo)) \
: (channels == 2 \
? stereo \
: \
stereo.ConvertToMono() \
))
}
function borderBattle(clip l, clip c, float lAR, float cAR, float PARl, int col)
{
wMod = Abs(Round(((l.height*cAR)-(l.Height*lAR))/(2*PARl)))
hMod = Abs(Round(((float(l.width)/cAR)-(float(l.width)/lAR))/2*PARl))
l = l.convertToRGB32
l = (lAR >= cAR) ? l.AddBorders(0,hMod,0,hMod, color=col)
\ : l.AddBorders(wMod,0,wMod,0, color=col)
return l
}
function cropBattle (clip l, clip c, float lAR, float cAR, float PARl)
{
wMod = Abs(Round(((l.height*cAR)-(l.Height*lAR))/(2*PARl)))
hMod = Abs(Round(((float(l.width)/cAR)-(float(l.width)/lAR))/2*PARl))
l = l.convertToRGB32
l = (lAR < cAR) ? l.Crop(0,hMod,0,-hMod)
\ : l.Crop(wMod,0,-wMod,0)
return l
}
function gpSplice(clip c, clip l, float "PARc", float "PARl", float "MaxARError" \
, float "MaxSpeedMod", bool "silence", bool "keepAudioC", bool "keepAudioL" \
, string "customFuncC", string "customFuncL", string "Resampler", int "BGcolour" \
, string "Resizer", int "destW", int "destH", string "Position", int "sRate", int "aChannels"\
, clip "ReplacementAudioTrack", string "mod")
{
PARc = Default(PARc, 1.0)
PARl = Default(PARl, 1.0)
MaxARError = Default(MaxARError, 0)
MaxSpeedMod = Default(MaxSpeedMod, 5.0)
silent = (c.AudioChannels == 0) ? True : False
silence = Default(silence, silent)
keepAudioC = Default(keepAudioC, (!silence))
keepAudioL = Default(keepAudioL, (!silence))
dftRate = c.hasAudio ? c.AudioRate \
: l.hasAudio ? l.audioRate : 48000
sRate = Default(sRate, dftRate)
dftChans = c.hasAudio ? c.AudioChannels \
: l.hasAudio ? l.AudioChannels : 2
aChannels = Default(aChannels, dftChans)
Resizer = Default(Resizer, "Spline36Resize")
Resampler = Default (Resampler, "ResampleAudio")
customFuncC = Default(customFuncC, "none")
customFuncL = Default(customFuncL, "none")
Position = Default(Position, "before")
BGcolour = Default(BGcolour, 000000)
destW = Default(destW, c.width)
destH = Default(destH, c.Height)
ReplacementAudioTrack = Default(ReplacementAudioTrack, BlankClip.killAudio)
#Mod = [ Crop | Pad (AddBorders) ]
mod = Default(mod, "pad")
cAR = float(c.width)/c.height * PARc
lAR = float(l.width)/l.height * PARl
#parC=
#parL=
#Eval User defined func
l = (customFuncL == "none") ? l : Eval ("l."+customFuncL)
c = (customFuncC == "none") ? c : Eval ("c."+customFuncC)
# If replacement audio track exists, kill All Audio
# If l does not have audio but want to keep audio of c, dub silent audio to l
# If l has audio && want to keep c audio but not l audio, replace l audio with silent audio
# All other cases, keep original l audio (or original lack of audio)
l = (!(l.hasAudio) && (KeepAudioC || KeepAudioL)) \
|| ((l.hasAudio) && KeepAudioC && !KeepAudioL) ? \
AudioDub(l.KillAudio,BlankClip(l, audio_rate=sRate, channels=aChannels)) \
: (ReplacementAudioTrack.hasAudio) || (!KeepAudioC && !KeepAudioL) ? l.killAudio\
: l
# If replacement audio track exists, kill audio
# If c does not have audio but want to keep audio of l, dub silent audio to c
# If c has audio && want to keep l audio but not c audio, replace c audio with silent audio
# All other cases, keep original c audio (or lack of audio)
c = ((!(c.hasAudio) && (KeepAudioC || KeepAudioL)) \
|| ((c.hasAudio) && KeepAudioL && !KeepAudioC )) ? \
AudioDub(c.KillAudio,BlankClip(c, audio_rate=sRate, channels=aChannels)) \
: (ReplacementAudioTrack.hasAudio) || (!KeepAudioC && !KeepAudioL) ? c.killAudio\
: c
#Match Audio Channels
##############################################
#Expand this.
l = (c.AudioChannels == l.audioChannels) ? l: \
(c.hasAudio) && (l.AudioChannels==2) ? \
AudioDub(l.killAudio,AudioMakerST(c.AudioChannels, l)) \
: !(c.hasAudio) ? l.killAudio \
: Assert("Need Stereo Audio to use AudioMaker, Hope to fix soon")
##############################################
# Match Framerate
#If framerate difference greater than acceptable; change fps (decimate duplicate),
#else speedup / slowdown to match film.
l = (c.FramerateNumerator == l.FramerateNumerator) && (c.FramerateDenominator == l.FramerateDenominator) ? l \
: (l.Framerate > c.Framerate*(plus(maxSpeedMod)) \
|| (l.Framerate < c.Framerate*(minus(maxSpeedMod))) ? \
l.ChangeFPS(c.FramerateNumerator , c.FramerateDenominator, true) \
: l.AssumeFPS(c.FramerateNumerator , c.FramerateDenominator, true))
# Is AR discrepancy acceptable?
mod = (cAR < lAR*minus(maxARError)) \
|| (cAR > lAR*plus(maxARError)) ? \
mod : "none"
#Crop or Pad to match Source AR
l = (mod == "none") ? l \
: (mod == "pad") ? l.borderBattle(c, lAR,cAr, PARl, BGcolour) \
: (mod=="crop") ? l.cropBattle(c, lAR, cAR, PARl) \
: l
#Match Frame Dimensions
l = Eval ("l."+Resizer+"(destW,destH)")
c = Eval ("c."+Resizer+"(destW,destH)")
#Match Colourspace
l = ( (c.IsYV12) ? ConvertToYV12(l) :
\ (c.IsRGB32) ? ConvertToRGB32(l) :
\ (c.IsRGB24) ? ConvertToRGB24(l) :
\ (c.IsYUY2) ? ConvertToYUY2(l) :
\ (c.IsYUV) ? ConvertToYUV(l) :
\ (c.IsRGB) ? ConvertToRGB(l) : l)
#Match Sample Rate
c = !(c.hasAudio) ? c : Eval ("c."+Resampler+"(sRate)")
l = (!(c.hasAudio) || (c.Audiorate == l.Audiorate)) ? l : Eval ("l."+Resampler+"(sRate)")
#Match AudioBits
l = (!(c.hasAudio) || (c.Audiobits == l.Audiobits)) ? l:
\ (c.Audiobits == 16) ? l.ConvertAudioTo16bit :
\ (c.Audiobits == 24) ?l.ConvertAudioTo24bit :
\ (c.Audiobits == 32) ?l.ConvertAudioTo32bit :
\ (c.Audiobits == 8) ?l.ConvertAudioTo8bit : l
######
##Splice
######
c = (Position == "before") ? l++c \
: (Position == "after") ? c++l \
: (Position == "middle") ? c.Trim(0,c.framecount/2)++l++c.Trim(c.framecount/2+1, c.framecount) \
: l++c
c = (ReplacementAudioTrack.hasAudio) ? Eval ("AudioDubEx(c,ReplacementAudioTrack)."+Resampler+"(sRate)") : c
return c
}
Usage
ClipWithDesirableProperties = ...
OtherClip = ...
ClipWithDesirableProperties.gpSplice(OtherClip)
The main problem I have is with matching audio channels. The way I am doing it now assumes the clip to be modified is originally stereo that can be built up (cheaply) to any number of channels, but I need to find an elegant way to be able to go from any number of channels to any other number of channels.
These functions from tebasuna51 seem promising, but they are all from x channels to stereo. It seems like I will probably have to write one function per channelnumber pair per sourcetype.
Can anyone help? :)
function Dmix3Stereo(clip a) { # 3 Channels L,R,C or L,R,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
return MixAudio(flr, fcc, 0.5858, 0.4142)
}
function Dmix3Dpl(clip a) { # 3 Channels only L,R,S
flr = GetChannel(a, 1, 2)
sl = GetChannel(a, 3)
sr = Amplify(sl, -1.0)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.5858, 0.4142)
}
function Dmix4lStereo(clip a) { # 4 Channels L,R,C + LFE
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lfe = GetChannel(a, 4, 4)
clf = MixAudio(fcc, lfe, 0.2929, 0.2929)
return MixAudio(flr, clf, 0.4142, 1.0)
}
function Dmix4qStereo(clip a) { #4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
blr = GetChannel(a, 3, 4)
return MixAudio(flr, blr, 0.5, 0.5)
}
function Dmix4qDpl(clip a) { # 4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
bl = GetChannel(a, 3)
br = GetChannel(a, 4)
sl = MixAudio(bl, br, 0.2929, 0.2929)
sr = MixAudio(bl, br, -0.2929, -0.2929)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.4142, 1.0)
}
function Dmix4qDpl2(clip a) { # 4 Channels Quadro L,R,SL,SR
flr = GetChannel(a, 1, 2)
bl = GetChannel(a, 3)
br = GetChannel(a, 4)
sl = MixAudio(bl, br, 0.3714, 0.2144)
sr = MixAudio(bl, br, -0.2144, -0.3714)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 0.4142, 1.0)
}
function Dmix4sStereo(clip a) {# 4 Channels L,R,C,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.4142, 0.2929)
blr = GetChannel(a, 4, 4)
return MixAudio(flr, blr, 1.0, 0.2929)
}
function Dmix4sDpl(clip a) { # 4 Channels L,R,C,S
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.4142, 0.2929)
sl = GetChannel(a, 4)
sr = Amplify(sl, -1.0)
blr = MergeChannels(sl, sr)
return MixAudio(flr, blr, 1.0, 0.2929)
}
function Dmix5Stereo(clip a) { # 5 Channels L,R,C,SL,SR -> Stereo
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3694, 0.2612)
blr = GetChannel(a, 4, 5)
return MixAudio(lrc, blr, 1.0, 0.3694)
}
function Dmix5Dpl(clip a) { # 5 Channels L,R,C,SL,SR -> dpl
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3205, 0.2265)
bl = GetChannel(a, 4)
br = GetChannel(a, 5)
sl = MixAudio(bl, br, 0.2265, 0.2265)
sr = MixAudio(bl, br, -0.2265, -0.2265)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix5Dpl2(clip a) { # 5 Channels L,R,C,SL,SR -> dpl II
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3254, 0.2301)
bl = GetChannel(a, 4)
br = GetChannel(a, 5)
sl = MixAudio(bl, br, 0.2818, 0.1627)
sr = MixAudio(bl, br, -0.1627, -0.2818)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Stereo(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3694, 0.2612)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.3694)
}
function Dmix6Dpl(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3205, 0.2265)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2265, 0.2265)
sr = MixAudio(bl, br, -0.2265, -0.2265)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Dpl2(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.3254, 0.2301)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2818, 0.1627)
sr = MixAudio(bl, br, -0.1627, -0.2818)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6StereoLfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3)
lfe = GetChannel(a, 4)
lfc = MixAudio(fcc, lfe, 0.2071, 0.2071)
mix = MergeChannels(lfc, lfc)
lrc = MixAudio(flr, mix, 0.2929, 1.0)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.2929)
}
function Dmix6StereoLfe2(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2929, 0.2071)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.2071)
blr = GetChannel(a, 5, 6)
return MixAudio(lrc, blr, 1.0, 0.2929)
}
function Dmix6DplLfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2613, 0.1847)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.1847)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.1847, 0.1847)
sr = MixAudio(bl, br, -0.1847, -0.1847)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
}
function Dmix6Dpl2Lfe(clip a) {
flr = GetChannel(a, 1, 2)
fcc = GetChannel(a, 3, 3)
lrc = MixAudio(flr, fcc, 0.2646, 0.1870)
lfe = GetChannel(a, 4, 4)
lrc = MixAudio(lrc, lfe, 1.0, 0.1870)
bl = GetChannel(a, 5)
br = GetChannel(a, 6)
sl = MixAudio(bl, br, 0.2291, 0.1323)
sr = MixAudio(bl, br, -0.1323, -0.2291)
blr = MergeChannels(sl, sr)
return MixAudio(lrc, blr, 1.0, 1.0)
return MergeChannels(l, r)
}
Once I've fixed the audio issues I'm thinking of adding an option to pad / border with stretched & blurred edges of the video rather than a flat colour. I've seen it on television occasionally when they're putting 4:3 sources in a 16:9 frame. It generally looks crap, but could be useful for someone!