Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

pvoc.rb 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. # pvoc.rb -- pvoc.scm -> pvoc.rb
  2. # Translator: Michael Scholz <mi-scholz@users.sourceforge.net>
  3. # Created: 04/03/27 00:19:51
  4. # Changed: 14/11/14 08:58:16
  5. # versions of the Moore-Klingbeil-Trevisani-Edwards phase-vocoder
  6. #
  7. # class Pvocoder
  8. # initialize(fftsize, overlap, interp, analyze, edit, synthesize)
  9. # inspect
  10. # pvocoder(input)
  11. #
  12. # make_pvocoder(fftsize, overlap, interp, analyze, edit, synthesize)
  13. # pvocoder(pv, input)
  14. #
  15. # test_pv_1
  16. # test_pv_2(freq)
  17. # test_pv_3(time)
  18. # test_pv_4(gate)
  19. #
  20. # pvoc(*rest)
  21. require "ws"
  22. class Pvocoder
  23. def initialize(fftsize, overlap, interp, analyze, edit, synthesize)
  24. @output = interp
  25. @interp = interp
  26. @hop = overlap
  27. @filptr = 0
  28. @N = fftsize
  29. @window = make_fft_window(Hamming_window, fftsize)
  30. @window.scale!(2.0 / (0.54 * fftsize))
  31. @D = fftsize / overlap
  32. @in_data = nil
  33. @ampinc = make_vct(fftsize)
  34. @freqs = make_vct(fftsize)
  35. @amps = make_vct(fftsize / 2)
  36. @phaseinc = make_vct(fftsize / 2)
  37. @phases = make_vct(fftsize / 2)
  38. @lastphase = make_vct(fftsize / 2)
  39. @analyze = analyze
  40. @edit = edit
  41. @synthesize = synthesize
  42. end
  43. def inspect
  44. format("#<%s outctr: %d, interp: %d, \
  45. filptr: %d, N: %d, D: %d, in_data: %p>",
  46. self.class, @output, @interp, @filptr, @N, @D, @in_data)
  47. end
  48. def pvocoder(input)
  49. if @output >= @interp
  50. if @analyze
  51. @analyze.call(self, input)
  52. else
  53. vct_fill!(@freqs, 0.0)
  54. @output = 0
  55. if (not vct?(@in_data))
  56. @in_data = make_vct!(@N) do
  57. input.call
  58. end
  59. else
  60. vct_move!(@in_data, 0, @D)
  61. ((@N - @D)...@N).each do |i|
  62. @in_data[i] = input.call
  63. end
  64. end
  65. buf = @filptr % @N
  66. if buf.zero?
  67. vct_fill!(@ampinc, 0.0)
  68. vct_add!(@ampinc, @in_data)
  69. vct_multiply!(@ampinc, @window)
  70. else
  71. @N.times do |k|
  72. @ampinc[buf] = @window[k] * @in_data[k]
  73. buf += 1
  74. if buf >= @N
  75. buf = 0
  76. end
  77. end
  78. end
  79. @filptr += @D
  80. mus_fft(@ampinc, @freqs, @N, 1)
  81. rectangular2polar(@ampinc, @freqs)
  82. end
  83. if @edit
  84. @edit.call(self)
  85. else
  86. pscl = 1.0 / @D
  87. kscl = TWO_PI / @N
  88. (@N / 2).times do |k|
  89. phasediff = @freqs[k] - @lastphase[k]
  90. @lastphase[k] = @freqs[k]
  91. while phasediff > PI
  92. phasediff -= TWO_PI
  93. end
  94. while phasediff < -TWO_PI
  95. phasediff += TWO_PI
  96. end
  97. @freqs[k] = pscl * phasediff + k * kscl
  98. end
  99. end
  100. scl = 1.0 / @interp
  101. vct_subtract!(@ampinc, @amps)
  102. vct_subtract!(@freqs, @phaseinc)
  103. vct_scale!(@ampinc, scl)
  104. vct_scale!(@freqs, scl)
  105. end
  106. @output += 1
  107. if @synthesize
  108. @synthesize.call
  109. else
  110. vct_add!(@amps, @ampinc)
  111. vct_add!(@phaseinc, @freqs)
  112. vct_add!(@phases, @phaseinc)
  113. sine_bank(@amps, @phases)
  114. end
  115. end
  116. end
  117. add_help(:make_pvocoder,
  118. "make_pvocoder(fftsize, overlap, interp, analyze=false, \
  119. edit=false, synthesize=false) \
  120. Makes a new (Ruby-based, not CLM) phase-vocoder generator.")
  121. def make_pvocoder(fftsize = 512,
  122. overlap = 4,
  123. interp = 128,
  124. analyze = false,
  125. edit = false,
  126. synthesize = false)
  127. Pvocoder.new(fftsize, overlap, interp, analyze, edit, synthesize)
  128. end
  129. add_help(:pvocoder,
  130. "pvocoder(pv, input) \
  131. Is the phase-vocoder generator associated with make_pvocoder.")
  132. def pvocoder(pv, input)
  133. pv.pvocoder(input)
  134. end
  135. =begin
  136. let(open_sound("oboe.snd"),
  137. make_pvocoder(256, 4, 64),
  138. make_sampler(0)) do |ind, pv, rd|
  139. map_channel(lambda do |y| pvocoder(pv, rd) end)
  140. play(ind, :wait, true)
  141. save_sound_as("pvoc.snd", ind)
  142. revert_sound(ind)
  143. close_sound(ind)
  144. open_sound("pvoc.snd")
  145. end
  146. =end
  147. def test_pv_1
  148. pv = make_phase_vocoder(false, 512, 4, 128, 1.0, false, false, false)
  149. rd = make_sampler(0)
  150. map_channel(lambda do |y|
  151. phase_vocoder(pv,
  152. lambda do |dir|
  153. next_sample(rd)
  154. end)
  155. end)
  156. free_sampler(rd)
  157. end
  158. def test_pv_2(freq)
  159. pv = make_phase_vocoder(false, 512, 4, 128, freq, false, false, false)
  160. rd = make_sampler(0)
  161. map_channel(lambda do |y|
  162. phase_vocoder(pv,
  163. lambda do |dir|
  164. next_sample(rd)
  165. end)
  166. end)
  167. free_sampler(rd)
  168. end
  169. def test_pv_3(time)
  170. pv = make_phase_vocoder(false, 512, 4, (time * 128.0).floor,
  171. 1.0, false, false, false)
  172. rd = make_sampler(0)
  173. len = (time * framples()).floor
  174. data = make_vct!(len) do
  175. phase_vocoder(pv,
  176. lambda do |dir|
  177. next_sample(rd)
  178. end)
  179. end
  180. free_sampler(rd)
  181. vct2channel(data, 0, len)
  182. end
  183. def test_pv_4(gate)
  184. pv = make_phase_vocoder(false,
  185. 512, 4, 128, 1.0,
  186. false,
  187. lambda do |v|
  188. phase_vocoder_amp_increments(v).map! do |val|
  189. if val < gate
  190. 0.0
  191. else
  192. val
  193. end
  194. true
  195. end
  196. end, false)
  197. rd = make_sampler(0)
  198. map_channel(lambda do |y|
  199. phase_vocoder(pv,
  200. lambda do |dir|
  201. next_sample(rd)
  202. end)
  203. end)
  204. free_sampler(rd)
  205. end
  206. # another version of the phase vocoder
  207. add_help(:pvoc,
  208. "pvoc(*rest)
  209. :fftsize = 512
  210. :overlap = 4
  211. :time = 1.0
  212. :pitch = 1.0
  213. :gate = 0.0
  214. :hoffset = 0.0
  215. :snd = false
  216. :chn = false
  217. Applies the phase vocoder algorithm to the current sound (i.e. fft analysis, \
  218. oscil bank resynthesis). \
  219. TIME specifies the time dilation ratio, \
  220. PITCH specifies the pitch transposition ratio, \
  221. GATE specifies a resynthesis gate in dB (partials with \
  222. amplitudes lower than the gate value will not be synthesized), \
  223. HOFFSET is a pitch offset in Hz.")
  224. def pvoc(*rest)
  225. fftsize, overlap, time, pitch, gate, hoffset, snd, chn = nil
  226. optkey(rest, binding,
  227. [:fftsize, 512],
  228. [:overlap, 4],
  229. [:time, 1.0],
  230. [:pitch, 1.0],
  231. [:gate, 0.0],
  232. [:hoffset, 0.0],
  233. [:snd, false],
  234. [:chn, false])
  235. len = framples(snd, chn)
  236. filptr = 0
  237. sr = srate(snd)
  238. fftsize2 = (fftsize / 2.0).floor
  239. d = fftsize / overlap
  240. interp = d * time
  241. syngate = gate.zero? ? 0.0 : (10 ** (-gate.abs / 20.0))
  242. poffset = hz2radians(hoffset)
  243. window = make_fft_window(Hamming_window, fftsize)
  244. fdr = make_vct(fftsize)
  245. fdi = make_vct(fftsize)
  246. lastphase = make_vct(fftsize2)
  247. lastamp = make_vct(fftsize2)
  248. lastfreq = make_vct(fftsize2)
  249. ampinc = make_vct(fftsize2)
  250. freqinc = make_vct(fftsize2)
  251. fundamental = TWO_PI / fftsize
  252. output = interp
  253. # resynth_oscils = make_array(fftsize2) do
  254. # make_oscil(:frequency, 0)
  255. # end
  256. outlen = (time * len).floor
  257. in_data = channel2vct(0, fftsize * 2, snd, chn)
  258. in_data_beg = 0
  259. vct_scale!(window, 2.0 / (0.54 * fftsize))
  260. obank = make_oscil_bank(lastfreq, make_vct(fftsize2, 0.0), lastamp)
  261. out_data = make_vct([len, outlen].max)
  262. out_data.length.times do |i|
  263. if output >= interp
  264. output = 0
  265. buffix = filptr % fftsize
  266. vct_fill!(lastamp, 0.0)
  267. vct_fill!(lastfreq, 0.0)
  268. vct_add!(lastamp, fdr)
  269. vct_add!(lastfreq, fdi)
  270. fftsize.times do |k|
  271. fdr[buffix] = window[k] * in_data[filptr - in_data_beg]
  272. filptr += 1
  273. buffix += 1
  274. if buffix >= fftsize
  275. buffix = 0
  276. end
  277. end
  278. filptr -= fftsize - d
  279. if filptr > in_data_beg + fftsize
  280. in_data_beg = filptr
  281. in_data = channel2vct(in_data_beg, fftsize * 2, snd, chn)
  282. end
  283. vct_fill!(fdi, 0.0)
  284. mus_fft(fdr, fdi, fftsize, 1)
  285. fftsize2.times do |k|
  286. a = fdr[k]
  287. b = fdi[k]
  288. mag = sqrt(a * a + b * b)
  289. phase = 0
  290. phasediff = 0
  291. fdr[k] = mag
  292. if mag > 0
  293. phase = -atan2(b, a)
  294. phasediff = phase - lastphase[k]
  295. lastphase[k] = phase
  296. while phasediff > PI
  297. phasediff -= TWO_PI
  298. end
  299. while phasediff < -PI
  300. phasediff += TWO_PI
  301. end
  302. end
  303. fdi[k] = pitch *
  304. ((phasediff * sr) / (d * sr) + k * fundamental + poffset)
  305. if fdr[k] < syngate
  306. fdr[k] = 0.0
  307. end
  308. ampinc[k] = (fdr[k] - lastamp[k]) / interp
  309. freqinc[k] = (fdi[k] - lastfreq[k]) / interp
  310. end
  311. end
  312. output += 1
  313. vct_add!(lastamp, ampinc)
  314. vct_add!(lastfreq, freqinc)
  315. # old_oscil_bank from extensions.rb
  316. # out_data[i] = old_oscil_bank(lastamp, resynth_oscils, lastfreq)
  317. out_data[i] = oscil_bank(obank)
  318. end
  319. vct2channel(out_data, 0, out_data.length)
  320. end
  321. # pvoc.rb ends here