Skip to content

arseniiv/lua-pieces

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lua-pieces

Simple libraries to use in LuaJIT (and, for example, protoplug). Included are a couple tests that run on import.

I mostly checked these in Try It Online and protoplug (Sintel's fork, though it shouldn't differ on the internal side of things at all).

Complex numbers

Rudimentary complex number support: many elementary functions such as trigonometry or general-purpose exp and log, aren't implemented. Only what was deemed to be useful in signal processing at the time was added.

cplx = require("path/to/libraries/cplx_05deg")

z1 = cplx.new(2, 3)          -- z1 = 2 + 3i
z2 = cplx.expi(math.pi / 3)  -- z2 = exp(iπ/3), "phasor"

-- components
print(z1.re, z1.im)

-- complex arithmetic + - * /
print(z1 + z2, z1 - z2, -z1, z1 * z2, z1 / z2)

-- raise to a real power ^
-- check near-equality
print(cplx.isclose(z2 ^ 3, cplx.new(-1)))

-- check near-equality of real numbers (for completeness)
print(cplx.isclose(math.sin(math.pi * 10000), 0))

Operations and notes

There are componentwise comparisons z1 == z2, z1 ~= z2 but they're as useless as for regular floats. Nonetheless when you really need them, here you go.

You can stringify with tostring(z).

Geometric operations with argument (phase) and absolute value:

  • z:conj() : cplx conjugate,
  • z:arg() : num argument,
  • z:norm() : num norm (absolute value),
  • z:sqr_norm() : num norm squared, tad more efficient than (z * z.conj()).re,
  • z:normalized() : cplx the same as z / cplx.new(z:norm()) but more efficient.

Powers aside from z ^ r:

  • z:sqr() : cplx the same as z * z but more efficient,
  • z:sqrt() : cplx the same as z ^ 0.5 but way more efficient (no trig involved).

Do not mix Lua numbers and these complex numbers, there are no implicit conversions. Instead, use:

  • cplx.new(x) to lift the real x into the complex domain,
  • z.re to get the real part of a complex number even if it's "already real",
  • z:times_r(x) to compute zx where z ∈ ℂ and x ∈ ℝ,
  • z:times_i(x = 1) to compute z ⋅ i x where z ∈ ℂ and x ∈ ℝ.

There's no polar form constructor, use cplx.expi(phase):times_r(r) or manual cplx.new(r * math.cos(phase), r * math.sin(phase)).

This library doesn't work in regular Lua because it uses C hypot function.

Scala SCL format support

If you're trying to use protoplug with custom tunings, it might be handy to paste the contents of an SCL file into your playground and let somebody else parse it for you. This library does exactly that!

scala = require("path/to/libraries/scala_05deg")

scl_text = [[
! Ancient Greek Archytas Enharmonic.scl
!
Archytas' Enharmonic
 7
!
 28/27
 16/15
 4/3
 3/2
 14/9
 8/5
 2/1
]]

intervals = scala.read_scl(scl_text)
assert(#intervals == 7 and intervals[-1] == 2)

frequencies = scala.midi_freqs(intervals)
assert(#frequencies == 128)

-- ... do something with `intervals` or `frequencies`

Interface

scala.middle_c() : num

Returns the standard middle C frequency in hertz (261.63...).

scala.read_scl(text : string) : array[num]

Reads an SCL-formatted string and returns a list of its intervals converted to linear domain, that is, no cent values: 3/2 gets through as 1.5, 833.1 cents will become 1.618....

Consider using multiline [[...]] strings for less hassle.

scala.midi_freqs(scale : array[num], start : num = 60, ref : num = 60, ref_freq : num = scala.middle_c(), first_note : num = 0, last_note : num = 127) : array[num]

Converts the scale you get from the previous function (or input manually as e.g. {9/8, 5/4, 4/3, 3/2, 5/3, 15/8, 2}) to a list of concrete frequencies for a lot of notes (the standard MIDI range 0...127 by default, but do remember Lua tables index from 1!).

Arguments start, ref and ref_freq are like in KBM: start is the note corresponding to the unison of the scale, wherever ref is the note assigned to the frequency ref_freq. Having them as 60, 69, 440 is the same as the defaults here, if you're using 12-note octave-repeating scales. Otherwise I treat the defaults as more universal (insofar one can treat "standard middle C" frequency as universal at all).

If you're using multi-channel extended-range retuning à la Pianoteq or Surge XT, you can specify a wider range of notes or something, via first_note and last_note. Though it should transpose in octaves instead of using a longer list of notes. Anyway it's there.

Other notes

This library may work in regular Lua, but why...

About

Simple libraries to use in LuaJIT (and, for example, protoplug)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages