Advertisement
Guest User

Untitled

a guest
Apr 20th, 2019
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.10 KB | None | 0 0
  1. #!/usr/bin/env luajit
  2.  
  3. -- Crappy demo: pushing audio samples with LuaJIT.
  4.  
  5. local function saw_osc(srate)
  6. local pos = 0
  7. return function(freq)
  8. local signal = pos - 0.25
  9. pos = math.fmod(pos + (0.5 * freq) / srate, 0.5)
  10. return signal
  11. end
  12. end
  13.  
  14. local function sine_osc(srate)
  15. local pos = 0
  16. return function(freq)
  17. local signal = 0.25 * math.sin(pos * math.pi / srate)
  18. pos = pos + freq
  19. return signal
  20. end
  21. end
  22.  
  23. local function waveshape(threshold, signal)
  24. if signal > threshold then
  25. return 0.1
  26. else
  27. return -0.1
  28. end
  29. end
  30.  
  31. local function silly_filter()
  32. local state0 = 0
  33. local state1 = 0
  34. return function(cfreq, signal)
  35. local fa = 1 - cfreq
  36. local fb = 0.5 * (1 + (1 / fa))
  37. state0 = state0 * fa + cfreq * (signal + fb * (state0 - state1))
  38. state1 = fa * state1 + cfreq * state0
  39. return state1
  40. end
  41. end
  42.  
  43. local function eg()
  44. local time = 0
  45. local charge = 0
  46. local state = 0
  47. local function trigger()
  48. time = 0
  49. state = 0
  50. end
  51. local function gen(attack, decay, sustain, release)
  52. local signal = charge
  53. if state == 0 then
  54. -- attack
  55. charge = charge + (1 - charge) * attack
  56. if 1 - charge < 0.01 then
  57. state = 1
  58. end
  59. elseif state == 1 then
  60. -- decay
  61. if decay < 0 then decay = 0 end
  62. charge = charge * (1 - decay)
  63. if charge < sustain then
  64. charge = sustain
  65. state = 2
  66. end
  67. elseif state == 2 then
  68. -- sustain
  69. if time > 2400 then
  70. state = 3
  71. end
  72. elseif state == 3 then
  73. -- release
  74. charge = charge * (1 - release)
  75. end
  76. time = time + 1
  77. return signal
  78. end
  79. return trigger, gen
  80. end
  81.  
  82. local function delay(len)
  83. local line = {}
  84. local pos = 1
  85. return function(input)
  86. local signal = line[pos] or 0.0
  87. line[pos] = input + signal * 0.8
  88. pos = pos % len + 1
  89. return signal
  90. end
  91. end
  92.  
  93. local notes = {
  94. 110.0,
  95. 130.81278265029931,
  96. 164.81377845643496,
  97. 220.0,
  98. 110.0,
  99. 130.81278265029931,
  100. 164.81377845643496,
  101. 220.0,
  102. 87.307057858250971,
  103. 110.0,
  104. 130.81278265029931,
  105. 164.81377845643496,
  106. 87.307057858250971,
  107. 110.0,
  108. 130.81278265029931,
  109. 164.81377845643496,
  110.  
  111. 110.0,
  112. 130.81278265029931,
  113. 164.81377845643496,
  114. 220.0,
  115. 110.0,
  116. 130.81278265029931,
  117. 164.81377845643496,
  118. 220.0,
  119. 82.40688922821748,
  120. 110.0,
  121. 130.81278265029931,
  122. 164.81377845643496,
  123. 82.40688922821748,
  124. 110.0,
  125. 130.81278265029931,
  126. 164.81377845643496
  127. }
  128.  
  129. local up_transpositions = {3, 5, 7}
  130. local down_transpositions = {-5, -7}
  131.  
  132. local ffi = require "ffi"
  133.  
  134. ffi.cdef(io.popen("cpp -P /usr/include/alsa/asoundlib.h"):read("*a"))
  135. local alsa = ffi.load "asound"
  136.  
  137. local function check(err, msg)
  138. if err < 0 then
  139. error(msg .. ": " .. ffi.string(alsa.snd_strerror(err)))
  140. end
  141. end
  142.  
  143. local handle = ffi.new("snd_pcm_t *[1]")
  144. local hw_params = ffi.new("snd_pcm_hw_params_t *[1]")
  145. local srate = ffi.new("unsigned[1]", 48000)
  146. local dir = ffi.new("int[1]", 0)
  147. check(alsa.snd_pcm_open(handle, "default", alsa.SND_PCM_STREAM_PLAYBACK, 0),
  148. "Cannot open audio output device")
  149. check(alsa.snd_pcm_hw_params_malloc(hw_params),
  150. "snd_pcm_hw_params_malloc failed")
  151. check(alsa.snd_pcm_hw_params_any(handle[0], hw_params[0]),
  152. "snd_pcm_hw_params_any failed")
  153. check(alsa.snd_pcm_hw_params_set_access(
  154. handle[0], hw_params[0], alsa.SND_PCM_ACCESS_RW_INTERLEAVED),
  155. "snd_pcm_hw_params_set_access failed")
  156. check(alsa.snd_pcm_hw_params_set_format(
  157. handle[0], hw_params[0], alsa.SND_PCM_FORMAT_S16),
  158. "snd_pcm_hw_params_set_format failed")
  159. check(alsa.snd_pcm_hw_params_set_rate_near(
  160. handle[0], hw_params[0], srate, dir),
  161. "snd_pcm_hw_params_set_rate_near failed")
  162. check(alsa.snd_pcm_hw_params_set_channels(
  163. handle[0], hw_params[0], 1),
  164. "snd_pcm_hw_params_set_channels failed")
  165. check(alsa.snd_pcm_hw_params(handle[0], hw_params[0]),
  166. "snd_pcm_hw_params failed")
  167. alsa.snd_pcm_hw_params_free(hw_params[0])
  168. check(alsa.snd_pcm_prepare(handle[0]), "snd_pcm_prepare failed")
  169.  
  170. local pos = 0
  171. local noten = 1
  172. local nsamp = srate[0]/10
  173. local samples = ffi.new("int16_t[?]", nsamp)
  174. local saw_osc_gen = saw_osc(srate[0])
  175. local lfo_gen = sine_osc(srate[0])
  176. local lfo2_gen = sine_osc(srate[0])
  177. local lfo3_gen = sine_osc(srate[0])
  178. local eg_trigger, eg_gen = eg()
  179. local silly_filter_gen = silly_filter()
  180. local de = delay(9000)
  181. local transpose = 0
  182. local transpose_ratio = 2
  183.  
  184. while true do
  185. for i = 0, nsamp-1 do
  186. if pos > 4800 then
  187. pos = 0
  188. eg_trigger()
  189. noten = noten + 1
  190. if noten > #notes then
  191. noten = 1
  192. local threshold = transpose / 48 + 0.5
  193. local delta
  194. if math.random() > threshold then
  195. delta = up_transpositions[math.random(1, #up_transpositions)]
  196. else
  197. delta = down_transpositions[math.random(1, #down_transpositions)]
  198. end
  199. transpose = transpose + delta
  200. transpose_ratio = math.pow(1.0594630943592953, transpose + 12)
  201. end
  202. end
  203. local saw_out = saw_osc_gen(notes[noten] * transpose_ratio)
  204. local square_out = waveshape(lfo_gen(0.25) * 0.7, saw_out)
  205. local mixer_out = 4.0 * saw_out * lfo2_gen(0.12) + 1.2 * square_out
  206. local eg_out = eg_gen(0.01, 0.00001 + (0.002*(lfo3_gen(0.05)+0.20)), 0.005, 0.0003)
  207. local vcf_out = silly_filter_gen(eg_out * 0.2 + 0.3, mixer_out * 0.01)
  208. local vca_out = vcf_out * (math.exp(eg_out)-1) * 5
  209. local delay_out = vca_out + 0.5 * de(vca_out)
  210. samples[i] = delay_out * 65000
  211. pos = pos + 1
  212. end
  213. check(alsa.snd_pcm_writei(handle[0], samples, nsamp),
  214. "snd_pcm_writei failed")
  215. end
  216. check(alsa.snd_pcm_drain(handle[0]),
  217. "snd_pcm_drain failed")
  218. check(alsa.snd_pcm_close(handle[0]),
  219. "snd_pcm_close failed")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement