paulstretch_mono.py (3160B)
1 # 2 # Paul's Extreme Sound Stretch (Paulstretch) - Python version 3 # 4 # by Nasca Octavian PAUL, Targu Mures, Romania 5 # http://www.paulnasca.com/ 6 # 7 # http://hypermammut.sourceforge.net/paulstretch/ 8 # 9 # this file is released under Public Domain 10 # 11 12 13 import sys 14 from numpy import * 15 import scipy.io.wavfile 16 import wave 17 18 def load_wav(filename): 19 try: 20 wavedata=scipy.io.wavfile.read(filename) 21 samplerate=int(wavedata[0]) 22 smp=wavedata[1]*(1.0/32768.0) 23 if len(smp.shape)>1: #convert to mono 24 smp=(smp[:,0]+smp[:,1])*0.5 25 return (samplerate,smp) 26 except: 27 print ("Error loading wav: "+filename) 28 return None 29 30 31 32 ######################################## 33 34 def paulstretch(samplerate,smp,stretch,windowsize_seconds,outfilename): 35 outfile=wave.open(outfilename,"wb") 36 outfile.setsampwidth(2) 37 outfile.setframerate(samplerate) 38 outfile.setnchannels(1) 39 40 #make sure that windowsize is even and larger than 16 41 windowsize=int(windowsize_seconds*samplerate) 42 if windowsize<16: 43 windowsize=16 44 windowsize=int(windowsize/2)*2 45 half_windowsize=int(windowsize/2) 46 47 #correct the end of the smp 48 end_size=int(samplerate*0.05) 49 if end_size<16: 50 end_size=16 51 smp[len(smp)-end_size:len(smp)]*=linspace(1,0,end_size) 52 53 54 #compute the displacement inside the input file 55 start_pos=0.0 56 displace_pos=(windowsize*0.5)/stretch 57 58 #create Hann window 59 window=0.5-cos(arange(windowsize,dtype='float')*2.0*pi/(windowsize-1))*0.5 60 61 old_windowed_buf=zeros(windowsize) 62 hinv_sqrt2=(1+sqrt(0.5))*0.5 63 hinv_buf=hinv_sqrt2-(1.0-hinv_sqrt2)*cos(arange(half_windowsize,dtype='float')*2.0*pi/half_windowsize) 64 65 while True: 66 67 #get the windowed buffer 68 istart_pos=int(floor(start_pos)) 69 buf=smp[istart_pos:istart_pos+windowsize] 70 if len(buf)<windowsize: 71 buf=append(buf,zeros(windowsize-len(buf))) 72 buf=buf*window 73 74 #get the amplitudes of the frequency components and discard the phases 75 freqs=abs(fft.rfft(buf)) 76 77 #randomize the phases by multiplication with a random complex number with modulus=1 78 ph=random.uniform(0,2*pi,len(freqs))*1j 79 freqs=freqs*exp(ph) 80 81 #do the inverse FFT 82 buf=fft.irfft(freqs) 83 84 #window again the output buffer 85 buf*=window 86 87 88 #overlap-add the output 89 output=buf[0:half_windowsize]+old_windowed_buf[half_windowsize:windowsize] 90 old_windowed_buf=buf 91 92 #remove the resulted amplitude modulation 93 output*=hinv_buf 94 95 #clamp the values to -1..1 96 output[output>1.0]=1.0 97 output[output<-1.0]=-1.0 98 99 #write the output to wav file 100 outfile.writeframes(int16(output*32767.0).tostring()) 101 102 start_pos+=displace_pos 103 if start_pos>=len(smp): 104 print ("100 %") 105 break 106 sys.stdout.write ("%d %% \r" % int(100.0*start_pos/len(smp))) 107 sys.stdout.flush() 108 109 outfile.close() 110 ######################################## 111 112 (samplerate,smp)=load_wav("input.wav") 113 114 paulstretch(samplerate,smp,8.0,0.25,"out.wav") 115 116 117