Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env luajit
- -- Crappy demo: pushing audio samples with LuaJIT.
- local function saw_osc(srate)
- local pos = 0
- return function(freq)
- local signal = pos - 0.25
- pos = math.fmod(pos + (0.5 * freq) / srate, 0.5)
- return signal
- end
- end
- local function sine_osc(srate)
- local pos = 0
- return function(freq)
- local signal = 0.25 * math.sin(pos * math.pi / srate)
- pos = pos + freq
- return signal
- end
- end
- local function waveshape(threshold, signal)
- if signal > threshold then
- return 0.1
- else
- return -0.1
- end
- end
- local function silly_filter()
- local state0 = 0
- local state1 = 0
- return function(cfreq, signal)
- local fa = 1 - cfreq
- local fb = 0.5 * (1 + (1 / fa))
- state0 = state0 * fa + cfreq * (signal + fb * (state0 - state1))
- state1 = fa * state1 + cfreq * state0
- return state1
- end
- end
- local function eg()
- local time = 0
- local charge = 0
- local state = 0
- local function trigger()
- time = 0
- state = 0
- end
- local function gen(attack, decay, sustain, release)
- local signal = charge
- if state == 0 then
- -- attack
- charge = charge + (1 - charge) * attack
- if 1 - charge < 0.01 then
- state = 1
- end
- elseif state == 1 then
- -- decay
- if decay < 0 then decay = 0 end
- charge = charge * (1 - decay)
- if charge < sustain then
- charge = sustain
- state = 2
- end
- elseif state == 2 then
- -- sustain
- if time > 2400 then
- state = 3
- end
- elseif state == 3 then
- -- release
- charge = charge * (1 - release)
- end
- time = time + 1
- return signal
- end
- return trigger, gen
- end
- local function delay(len)
- local line = {}
- local pos = 1
- return function(input)
- local signal = line[pos] or 0.0
- line[pos] = input + signal * 0.8
- pos = pos % len + 1
- return signal
- end
- end
- local notes = {
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 220.0,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 220.0,
- 87.307057858250971,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 87.307057858250971,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 220.0,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 220.0,
- 82.40688922821748,
- 110.0,
- 130.81278265029931,
- 164.81377845643496,
- 82.40688922821748,
- 110.0,
- 130.81278265029931,
- 164.81377845643496
- }
- local up_transpositions = {3, 5, 7}
- local down_transpositions = {-5, -7}
- local ffi = require "ffi"
- ffi.cdef(io.popen("cpp -P /usr/include/alsa/asoundlib.h"):read("*a"))
- local alsa = ffi.load "asound"
- local function check(err, msg)
- if err < 0 then
- error(msg .. ": " .. ffi.string(alsa.snd_strerror(err)))
- end
- end
- local handle = ffi.new("snd_pcm_t *[1]")
- local hw_params = ffi.new("snd_pcm_hw_params_t *[1]")
- local srate = ffi.new("unsigned[1]", 48000)
- local dir = ffi.new("int[1]", 0)
- check(alsa.snd_pcm_open(handle, "default", alsa.SND_PCM_STREAM_PLAYBACK, 0),
- "Cannot open audio output device")
- check(alsa.snd_pcm_hw_params_malloc(hw_params),
- "snd_pcm_hw_params_malloc failed")
- check(alsa.snd_pcm_hw_params_any(handle[0], hw_params[0]),
- "snd_pcm_hw_params_any failed")
- check(alsa.snd_pcm_hw_params_set_access(
- handle[0], hw_params[0], alsa.SND_PCM_ACCESS_RW_INTERLEAVED),
- "snd_pcm_hw_params_set_access failed")
- check(alsa.snd_pcm_hw_params_set_format(
- handle[0], hw_params[0], alsa.SND_PCM_FORMAT_S16),
- "snd_pcm_hw_params_set_format failed")
- check(alsa.snd_pcm_hw_params_set_rate_near(
- handle[0], hw_params[0], srate, dir),
- "snd_pcm_hw_params_set_rate_near failed")
- check(alsa.snd_pcm_hw_params_set_channels(
- handle[0], hw_params[0], 1),
- "snd_pcm_hw_params_set_channels failed")
- check(alsa.snd_pcm_hw_params(handle[0], hw_params[0]),
- "snd_pcm_hw_params failed")
- alsa.snd_pcm_hw_params_free(hw_params[0])
- check(alsa.snd_pcm_prepare(handle[0]), "snd_pcm_prepare failed")
- local pos = 0
- local noten = 1
- local nsamp = srate[0]/10
- local samples = ffi.new("int16_t[?]", nsamp)
- local saw_osc_gen = saw_osc(srate[0])
- local lfo_gen = sine_osc(srate[0])
- local lfo2_gen = sine_osc(srate[0])
- local lfo3_gen = sine_osc(srate[0])
- local eg_trigger, eg_gen = eg()
- local silly_filter_gen = silly_filter()
- local de = delay(9000)
- local transpose = 0
- local transpose_ratio = 2
- while true do
- for i = 0, nsamp-1 do
- if pos > 4800 then
- pos = 0
- eg_trigger()
- noten = noten + 1
- if noten > #notes then
- noten = 1
- local threshold = transpose / 48 + 0.5
- local delta
- if math.random() > threshold then
- delta = up_transpositions[math.random(1, #up_transpositions)]
- else
- delta = down_transpositions[math.random(1, #down_transpositions)]
- end
- transpose = transpose + delta
- transpose_ratio = math.pow(1.0594630943592953, transpose + 12)
- end
- end
- local saw_out = saw_osc_gen(notes[noten] * transpose_ratio)
- local square_out = waveshape(lfo_gen(0.25) * 0.7, saw_out)
- local mixer_out = 4.0 * saw_out * lfo2_gen(0.12) + 1.2 * square_out
- local eg_out = eg_gen(0.01, 0.00001 + (0.002*(lfo3_gen(0.05)+0.20)), 0.005, 0.0003)
- local vcf_out = silly_filter_gen(eg_out * 0.2 + 0.3, mixer_out * 0.01)
- local vca_out = vcf_out * (math.exp(eg_out)-1) * 5
- local delay_out = vca_out + 0.5 * de(vca_out)
- samples[i] = delay_out * 65000
- pos = pos + 1
- end
- check(alsa.snd_pcm_writei(handle[0], samples, nsamp),
- "snd_pcm_writei failed")
- end
- check(alsa.snd_pcm_drain(handle[0]),
- "snd_pcm_drain failed")
- check(alsa.snd_pcm_close(handle[0]),
- "snd_pcm_close failed")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement