I played a quick set for a Toyota themed party recently and put this track together for that
https://loganmcbroom.bandcamp.com/track/toyota-abstract
https://loganmcbroom.bandcamp.com/track/toyota-abstract
Release 8 is now available:
https://unstablesound.net/cdpforum/index.php?topic=264.0
This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.
Show posts Menu
local TVPairs = {}
function TVPairs:new( o )
o = o or {}
setmetatable( o, self )
self.__index = self
return o:sort()
end
function TVPairs:__tostring()
local out = ""
for i = 1, #self do
out = out .. self[i][1] .. " " .. self[i][2] .. "\n"
end
return out
end
function TVPairs:__call( t )
if #self == 0 or self[1][1] > t or self[#self][1] < t then return 0 end
for i = 2, #self do
if self[i][1] >= t then --lerp it
local x1, x2, y1, y2 = self[i-1][1], self[i][1], self[i-1][2], self[i][2]
local m = (y1-y2)/(x1-x2)
return m*(t-x1) + y1
end
end
print "Error in TVPairs:_call"
end
--Math
local function tvp_operate( lhs, rhs, operation )
if type(lhs) == "number" then
local data = {}
for i = 1, #rhs do data[i] = {rhs[i][1], operation( rhs[i][2], lhs )} end
return TVPairs:new( data )
elseif type(rhs) == "number" then
local data = {}
for i = 1, #lhs do data[i] = {lhs[i][1], operation( lhs[i][2], rhs )} end
return TVPairs:new( data )
else
local times = {}
for i = 1, #lhs do times[i] = lhs[i][1] end
for i = 1, #rhs do times[i+#lhs] = rhs[i][1] end
table.sort( times )
for i = 1, #times - 1 do
if times[i] == times[i+1] then table.remove( times, i ) end
end
local data = {}
for i = 1, #times do
data[i] = { times[i], operation( lhs(times[i]), rhs(times[i]) ) }
end
return TVPairs:new( data )
end
end
function TVPairs:__unm()
local tvp = {}
for i = 1, #self do
tvp[i] = {self[i][1], -self[i][2]}
end
return TVPairs:new( tvp )
end
function TVPairs.__add( lhs, rhs ) return tvp_operate( lhs, rhs, function( a, b ) return a + b end ) end
function TVPairs.__sub( lhs, rhs ) return tvp_operate( lhs, rhs, function( a, b ) return a - b end ) end
function TVPairs.__mul( lhs, rhs ) return tvp_operate( lhs, rhs, function( a, b ) return a * b end ) end
function TVPairs.__div( lhs, rhs )
return tvp_operate( lhs, rhs, function( a, b )
if b == 0 then return 0
else return a / b
end
end )
end
function TVPairs.__mod( lhs, rhs ) --time shift
local data = {}
if type( lhs ) == "number" then
for i,v in ipairs(rhs) do data[i] = { rhs[i][1] + lhs, rhs[i][2] } end
else
for i,v in ipairs(lhs) do data[i] = { lhs[i][1] + rhs, lhs[i][2] } end
end
return TVPairs:new( data )
end
function TVPairs.__pow( lhs, rhs ) --convolution
local data = TVPairs:new()
for _,v in ipairs(lhs) do
data = data + ( ( rhs * v[2] ) % v[1] )
end
return TVPairs:new( data )
end
function TVPairs.__concat( lhs, rhs )
if getmetatable( lhs ) == TVPairs and getmetatable( rhs ) == TVPairs then --combining two TVPairs
local data = {}
for i = 1, #lhs do data[i ] = lhs[i] end
for i = 1, #rhs do data[i+#lhs] = rhs[i] end
table.sort( data, function( a, b ) return a[1] < b[1] end )
for i = 1, #data - 1 do
if data[i][1] == data[i+1][1] then table.remove( data, i+1 ) end
end
return TVPairs:new( data )
else -- Only one of the two was a TVPairs, assume the other can be converted to TVPairs
if getmetatable( lhs ) == TVPairs then return lhs .. TVPairs:new( rhs )
else return TVPairs:new( lhs ) .. rhs --It must be the case that rhs was TVPairs so don't bother checking
end
end
end
--Other
function TVPairs:sort() --Sort... appropriately
table.sort( self, function( a, b ) return a[1] < b[1] end )
return self
end
function TVPairs:compile() return compile( self ) end
function TVPairs:sample( length, rate, func ) return sample( length, rate, func ) end
function TVPairs:unsample() --returns a polynomial passing through all points in self
local function ToReducedRowEchelonForm ( M ) --From rosettacode
local lead = 1
local n_rows, n_cols = #M, #M[1]
for r = 1, n_rows do
if n_cols <= lead then break end
local i = r
while M[i][lead] == 0 do
i = i + 1
if n_rows == i then
i = r
lead = lead + 1
if n_cols == lead then break end
end
end
M[i], M[r] = M[r], M[i]
local m = M[r][lead]
for k = 1, n_cols do
M[r][k] = M[r][k] / m
end
for i = 1, n_rows do
if i ~= r then
local m = M[i][lead]
for k = 1, n_cols do
M[i][k] = M[i][k] - m * M[r][k]
end
end
end
lead = lead + 1
end
end
--determine coefficients by matrix reduction
local M = {}
for i = 1, #self do
M[i] = {}
for j = 1, #self do
M[i][j] = self[i][1]^(j-1)
end
M[i][#self + 1] = self[i][2]
end
ToReducedRowEchelonForm( M )
local coeff = {} --store in increasing degree order
for i = 1, #M do
coeff[i] = M[i][#M[i]]
end
return function( t )
local out = 0
for i = 1, #coeff do
out = out + coeff[i]*(t^(i-1))
end
return out
end
end
----------------------------------------------------------------------------------
function compile( ... )
local arg = {...}
local files = {}
for i = 1, #arg do
files[i] = altar_text( tostring( arg[i] ) )
end
return unpack( files )
end
function sample( length, rate, func )
local data = {}
local samples = math.floor( length / rate )
for i = 1, samples + 1 do
local t = rate * (i-1)
data[i] = {t, func(t)}
end
return TVPairs:new( data )
end
----------------------------------------------------------------------------------
local M = {}
M.TVPairs = TVPairs
M.compile = compile
M.sample = sample
return M
local tvp = require( "TVPairs" )
--Resample data at *10 resolution as a polynomial
local tr1 = tvp.TVPairs:new{ {0, 0}, {1, 1}, {2, 8}, {3, 6}, {4, 5}, {5, 4} }
local tr2 = tvp.sample( 5, .1, tr1:unsample() )
print( tostring( tr2 ) )
--Generate sinusoid TVPairs
function sample_sin( length, low, high, period, offset )
offset = offset or 0
local base = (low+high)/2.0
return tvp.sample( length, .1,
function( t )
return base + (high - base) * math.sin( (2.0*math.pi)*(t/period) + offset )
end
)
end