By moonlake
Sat Jun 15, 2024 6:22 pm
I wrote a little script for Pixilang, which is a portable scripting interpreter
( https://warmplace.ru/soft/pixilang/ ) available for a variety of platforms,
that takes two samples, "low" and "high", and resynthesises "low" with the phases/frequencies of "high", and substracts the result from "high", and saves both.
The result is two samples that can be blended seamlessly, switchlessly, for smooth velocity blending, without any unwanted cancellation or doubling effects-
Here is an example, the example is not ideal since the orginal samples were intended and recorded with aproximate same velocity (it seems), but still you get the effect.
note how for example the cymbals get more and less noisy, without any sample switches,
and without any phase cancellations - both samples match, and "low" plus "high" gives the original "high" sample exactly.
here is the code, if you wantt to try it out:
if you find this useful, and use it commercially, it would be nice if you would either support the author of Pixilang, or me, the author of the script, cause I am bitter poor.
Easiest way to support me is by buying one of my albums on Bandcamp or Mirlo which are linked in the music subforum.
Anything from paying a coffee to what ever its worth to you is very welcome.
( https://warmplace.ru/soft/pixilang/ ) available for a variety of platforms,
that takes two samples, "low" and "high", and resynthesises "low" with the phases/frequencies of "high", and substracts the result from "high", and saves both.
The result is two samples that can be blended seamlessly, switchlessly, for smooth velocity blending, without any unwanted cancellation or doubling effects-
Here is an example, the example is not ideal since the orginal samples were intended and recorded with aproximate same velocity (it seems), but still you get the effect.
note how for example the cymbals get more and less noisy, without any sample switches,
and without any phase cancellations - both samples match, and "low" plus "high" gives the original "high" sample exactly.
here is the code, if you wantt to try it out:
Code: Select all
// spectral velocity layering preparation resynth:
//
// takes two mono 16 bit .wav files, "wavlow" and "wavhigh", resynths a wave with phases of "wavhigh",
// and spectral envelope of "wavlow" and substracts the result from "wavhigh".
//
// resynthesized "high" wave can now be added to resynthesized "low" wave dynamically (for instance by velocity),
// smoothly blending from one wave to the other without phase cancellations:
// "infinite" velocity layers.
//
// good for drum, percussion, cymbal or piano samples or similar, but can also be used for experimentation.
//
// note:
// 1. the result is at least two times longer than the longer input wav and needs to be cut again
//
// v0.92 aingil 2024
//
//####### user parameters:
wavlow = load( "input_low.wav") // 16BIT MONO
wavhigh = load( "input_high.wav") // 16BIT MONO
savestr1 = "result_low.wav" // name and path for resynthesised lower wave, 16 bit mono
savestr2 = "result_add.wav" // name and path for resynthesised upper wave to add, 16 bit mono
gaindiv = 1000 // gain divider,
//###########################################################################################################
//######## init:
clear()
print("processing..." , 0 , 0, WHITE, TOP | LEFT )
frame()
if( get_xsize( wavlow ) < get_xsize( wavhigh ) ){
wavsize = get_xsize( wavhigh )
}else{
wavsize = get_xsize( wavlow )
}
ftpow = log2( wavsize ) div 1 + 1
ftsize = pow( 2, ftpow)
buflowr = new( ftsize, 1, FLOAT32 )
buflowi = new( ftsize, 1, FLOAT32 )
bufhighr = new( ftsize, 1, FLOAT32 )
bufhighi = new( ftsize, 1, FLOAT32 )
maglow = new( ftsize, 1, FLOAT32 )
maghigh = new( ftsize, 1, FLOAT32 )
phlow = new( ftsize, 1, FLOAT32 )
phhigh = new( ftsize, 1, FLOAT32 )
buftemp = new( ftsize, 1, FLOAT32 )
clean( buflowr)
clean( buflowi)
clean( bufhighr)
clean( bufhighi)
clean( cepslowi)
clean( cepshighi)
// processing mono:
// to spectrum:
convert_type( wavlow, FLOAT32)
convert_type( wavhigh, FLOAT32)
copy( buflowr, wavlow, 0, 0, get_xsize(wavlow), 1, 1, COPY_CLIPPING )
copy( bufhighr, wavhigh, 0, 0, get_xsize(wavhigh), 1, 1, COPY_CLIPPING )
fft( 0, buflowi, buflowr, ftsize)
fft( 0, bufhighi, bufhighr, ftsize)
op_cc( OP_COPY, buftemp, buflowi)
op_cc( OP_COPY, maglow, buflowr)
op_cc( OP_MUL, buftemp, buftemp)
op_cc( OP_MUL, maglow, maglow)
op_cc( OP_ADD, maglow, buftemp)
op_cc( OP_COPY, buftemp, bufhighi)
op_cc( OP_COPY, maghigh, bufhighr)
op_cc( OP_MUL, buftemp, buftemp)
op_cc( OP_MUL, maghigh, maghigh)
op_cc( OP_ADD, maghigh, buftemp)
for( i=0; i< ftsize; i+1){
maglow[ i ] = sqrt( maglow[ i ] )
maghigh[ i ] = sqrt( maghigh[ i ] )
phlow[ i ] = atan2( buflowi[ i ], buflowr[ i ])
phhigh[ i ] = atan2( bufhighi[ i ], bufhighr[ i ])
}
// resynth wav1 with phases of wav2 and spectral envelope of wav1
for( i=0; i< ftsize/2; i+1){
buflowr[ i ] = cos( phhigh[ i ] )* maglow[i] / gaindiv
buflowi[ i ] = sin( phhigh[ i ] )* maglow[i] / gaindiv
buflowr[ftsize/2-i-1] = 0
buflowi[ftsize/2-i-1] = 0
bufhighr[ i ] = cos( phhigh[ i ] )* maghigh[i] / gaindiv
bufhighi[ i ] = sin( phhigh[ i ] )* maghigh[i] / gaindiv
bufhighr[ftsize/2-i-1] = 0
bufhighi[ftsize/2-i-1] = 0
}
fft( 1, buflowi, buflowr, ftsize)
fft( 1, bufhighi, bufhighr, ftsize)
//###### save result:
clear()
print("saving..." , 0 , 0, WHITE, TOP | LEFT )
frame()
convert_type( buflowr, INT16)
convert_type( bufhighr, INT16)
op_cc( OP_SUB, bufhighr, buflowr)
save( buflowr, savestr1, FORMAT_WAVE )
save( bufhighr, savestr2, FORMAT_WAVE )
clear()
print("done." , 0 , 0, WHITE, TOP | LEFT )
frame(1000)
if you find this useful, and use it commercially, it would be nice if you would either support the author of Pixilang, or me, the author of the script, cause I am bitter poor.
Easiest way to support me is by buying one of my albums on Bandcamp or Mirlo which are linked in the music subforum.
Anything from paying a coffee to what ever its worth to you is very welcome.

