/posts  ·   /talks  ·   /boat  ·   /#30DayMapChallenge 2020 | 2022  ·  /About

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.

output image

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
;