# Needlework
A small drone piece exploring the Mandelbrot needle.
Composed with my libraries mandelbrot-symbolics
, mandelbrot-numerics
, mandelbrot-graphics
.
Soundtrack exported using libsndfile
.
# 1 Video
# 2 Source Code
A variant on a program that calculates the number of components of the Mandelbrot set that are on the real axis (see OEIS sequences A000048 and A051841).
#include <complex.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <mandelbrot-graphics.h>
#include <mandelbrot-numerics.h>
#include <mandelbrot-symbolics.h>
#include <sndfile.h>
int main(int argc, char **argv)
{
(void) argc;
(void) argv;
int width = 640;
int height = 360;
int maxiters = 100100;
double er = exp(2 * 3.141592653);
m_pixel_t black = m_pixel_rgba(0,0,0,1);
m_pixel_t grey = m_pixel_rgba(0.9,0.9,0.9,1);
m_pixel_t white = m_pixel_rgba(1,1,1,1);
m_d_colour_t *colour = m_d_colour_minimal_grid(white, black, white, grey);
m_image *image = m_image_new(width, height);
m_binangle b;
mpq_t q, qq, one;
m_binangle_init(&b);
mpq_init(q);
mpq_init(qq);
mpq_init(one);
mpq_set_ui(one, 1, 1);
long long period = 17;
long long mask = (1 << (period >> 1)) - 1;
long long total = 0;
long long real = 0;
long long bulb = 0;
long long den = (1ll << period) - 1;
int frame = 0;
float buffer[1600][2];
float sintab[1600][period];
float costab[1600][period];
for (int i = 0; i < 1600; ++i)
{
float window = (1 - cos(2 * M_PI * (i + 0.5) / 1600));
for (int j = 0; j < period; ++j)
{
sintab[i][j] = window * sin(2 * M_PI * (1 + j) * (i + 0.5) / 1600) / sqrt(1 + j);
costab[i][j] = window * cos(2 * M_PI * (1 + j) * (i + 0.5) / 1600) / sqrt(1 + j);
}
}
SF_INFO info = {0};
info.samplerate = 48000;
info.channels = 2;
info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
SNDFILE *out = sf_open("needlework.wav", SFM_WRITE, &info);
for (long long num = 1; 2 * num < den; ++num)
{
b.per.length = period;
mpz_set_si(b.per.bits, num);
m_binangle_to_rational(q, &b);
m_binangle_from_rational(&b, q);
if (b.per.length == period)
{
total++;
m_q_conjugate(qq, q);
mpq_sub(qq, one, qq);
if (mpq_equal(q, qq))
{
real++;
if ((period & 1) == 0 && ((~(num >> (period >> 1))) & mask) == (num & mask))
{
bulb++;
}
else
{
double _Complex c = m_d_exray_in_do(q, 8, 2 * 8 * period, 16);
m_d_nucleus(&c, c, period, 64);
double r = 16 * cabs(m_d_size(c, period));
m_d_transform *transform = m_d_transform_rectangular(width, height, c, r);
m_d_render_scanline(image, transform, er, maxiters, colour);
m_d_transform_delete(transform);
char filename[100];
snprintf(filename, sizeof(filename), "%04d.png", frame++);
m_image_save_png(image, filename);
memset(buffer, 0, sizeof(buffer));
for (int i = 0; i < 1600; ++i)
{
for (int j = 0; j < period; ++j)
{
if ((num >> (period-1 - j)) & 1)
{
buffer[i][0] += sintab[i][j];
buffer[i][1] += costab[i][j];
}
}
buffer[i][0] = sin(buffer[i][0]);
buffer[i][1] = sin(buffer[i][1]);
}
sf_writef_float(out, &buffer[0][0], 1600);
}
}
}
}
sf_close(out);
return 0;
}
# 3 Video Encoding
for pass in 1 2 3
do
ffmpeg -r 30 -i %04d.png \
-pix_fmt yuv420p -profile:v high -level:v 4.1 \
-b:v 2M -bf:v 2 -g:v 30 -movflags +faststart -pass $pass \
-y v.mp4
done
fdkaac -b 192k needlework.wav
ffmpeg -i v.mp4 -i needlework.m4a \
-codec:a copy -codec:v copy -movflags +faststart needlework.mp4
ffmpeg -ss 10 -i needlework.mp4 -frames:v 1 needlework.jpg