2022 / Day 27: Music
If I remember correctly then Vitalogy was my first ever official-official recording that I bought - a cassette recording and I think it cost a whopping 60 EEK (abt 3-4 EUR). I remember it was the summertime so it must have been 1995. At the time I did not have a CD player and CDs were almost 4-5 times the price - you simply could not afford them anyway. Vinyls could be found in only a few specialized shops mostly selling drum and bass and other electro music. And those were even more expensive. So in a way it is no wonder that still around those times as it had been for decades before aswell (and as I later learned, in the “western world” it was called) bootlegging was the way to get or hear new music - sharing yours and record tapes at your friends place (which by all means was essentially a copyright infringement, but times were different and nobody cared, or really understood what that meant). But anyway, that’s not what I wanted to talk about. Today’s entry for the challenge is a hommage to the band I guess “shaped my later teenage-years”.
So without any further ado:
SPIN THE BLACK CIRCLE!
We begin by constructing the letters
section of the vinyl label with
st_letters composing them as
two separate lines (of text) and shifting them away from each other
with st_translate so the
center of the disk (for the pin-hole) would be between them.
letter_bounds
builds the vinyl label area using a combination of
st_buffer
and st_minimumboundingradius.
For song tracklines in tracks
we’re creating a spiral set in the center of our
would be vinyl disk pin-hole. The solution is derived from a
GIS StackExchange answer by
Martin Davies (the original author of JTS, if I’m not mistaken). Except for
some variable numbers that I changed there to make it suitable for this
use-case the only real change was to switch the spiral around to go
counter-clockwise (because the vinyl itself is moving clock-wise). And also
let’s add a bit of random()
to every point so we’ll get the wobbling lines
as if on a real vinyl :)
Between every track
there is a moment of silence
which are simply
st_buffers of the pin-hole center
set at every 25% of the whole disk width and then
st_boundary to convert them to
lines.
And finally we pull everything together for animating it with
QGIS temporal controller
using a generate_series
to do a 360 degree turn of the vinyl.
with
letters as (
select
st_union(geom) as geom
from (
select
st_translate(
l.geom,
0 - ((st_xmax(l.geom)-st_ymin(l.geom))/2.0),
(st_ymax(l.geom)-st_ymin(l.geom))/0.5
) as geom,
st_xmax(l.geom)-st_ymin(l.geom) as width
from (
select
st_letters('VIVA LA') as geom
) l
union all
select
st_translate(
l.geom,
0 - ((st_xmax(l.geom)-st_ymin(l.geom))/2.0),
-1*((st_ymax(l.geom)-st_ymin(l.geom))/1.5)
) as geom,
st_xmax(l.geom)-st_ymin(l.geom) as width
from (
select
st_letters('VINYL') as geom
) l
) t
),
letter_bounds as (
select
st_difference(
st_buffer(
c,
w.val,
'quad_segs=80'
),
st_buffer(
c,
mbr.radius/10.0
)
) as geom,
c, w.val as w
from
letters
join lateral
st_centroid(geom) c on true
join lateral
st_minimumboundingradius(geom) mbr on true
join lateral (
select mbr.radius*1.5 val
) w on true
),
tracks as (
/* create the vinyl song track lines as a spiral adding a random
glitch to every node*/
select
d.geom
from (
select
st_difference(t.geom, a) as geom
from (
select
st_makeline(
st_point(
st_x(lb.c) +
(15.0/80.0)*t* -cos(t*(2*pi()/80.0))+
10.0*random(),
st_y(lb.c) +
(15.0/80.0)*t* sin(t*(2*pi()/80.0))+
10.0*random()
) order by t
) as geom
from
letter_bounds lb,
generate_series(0, 160*25, 1) t
) t, letter_bounds lb
join lateral
st_exteriorring(lb.geom) ex on true
join lateral
st_buildarea(ex) a on true
) tracks
join lateral
st_dump(geom) d on true
order by
st_length(d.geom) desc
limit 1
),
silence as (
/* create "silence-stripes" on the edge, and between tracks*/
select
s,
st_boundary(
st_buffer(
lb.c,
((((st_xmax(t.geom)-st_xmin(t.geom))/pi())+lb.w) * s/100.0),
'quad_segs=80'
)
) as geom
from
tracks t,
letter_bounds lb,
generate_series(0,100, 25) s
where
s > 25
)
/* And pull all together*/
select
row_number() over()::int as oid, f.px, f.cl,
('2022.11.27 '||(((7.98 + s::numeric / 3600.0)||' hours')::interval)::time)::timestamp,
st_rotate(f.geom,radians(360-s), lb.c) as geom
from
letter_bounds lb,
generate_series (1,360, 5) s, (
select
case
when s = 100 then 20
else 5
end as px,
'silence' as cl,
geom
from silence
union all
select
2 as px,
'track' as cl,
geom
from tracks
union all
select
20 as px,
'letter_bounds' as cl,
b as geom
from
letter_bounds
join lateral
st_dumprings(geom) r on true
join lateral
st_boundary(r.geom) b on true
union all
select
3 as px,
'letters' as cl,
b as geom
from
letters
join lateral
st_dump(letters.geom) d on true
join lateral
st_dumprings(d.geom) r on true
join lateral
st_boundary(r.geom) b on true
) f
;