diff --git a/site/writings/digitalfreedom.org b/site/writings/digitalfreedom.org new file mode 100644 index 0000000..e3bbd1e --- /dev/null +++ b/site/writings/digitalfreedom.org @@ -0,0 +1,71 @@ +#+title: Hardware freedom +#&summary +A discussion about hardware freedom. Contains comparisons with software +freedom. +#& +#+license: wtfpl + + +https://www.fsf.org/resources/hw/endorsement/criteria +https://www.fsf.org/campaigns/free-bios.html +https://www.gnu.org/philosophy/android-and-users-freedom.html +http://projects.goldelico.com/p/gta04-main/page/FirmwareInjector/?rev=322 +http://www.oreillynet.com/linux/blog/2007/08/the_four_freedoms_applied_to_h.html +http://www.boingboing.net/2010/09/19/intel-drm-a-crippled.html +http://lists.en.qi-hardware.com/pipermail/discussion/2010-January/001635.html +http://www.ofb.biz/safari/article/353.html +http://arstechnica.com/business/news/2006/12/8428.ars +http://distrowatch.com/weekly.php?issue=20100614#feature +http://libreplanet.org/wiki/When_should_firmware_be_free +http://www.datamation.com/osrc/article.php/3787736/Proprietary-Firmware-and-the-Pursuit-of-a-Free-Kernel.htm +https://lwn.net/Articles/352555/ +https://lwn.net/Articles/460654/ +http://lists.goldelico.com/pipermail/gta04-owner/2011-October/000375.html +http://lists.goldelico.com/pipermail/gta04-owner/2011-September/000325.html + + + +centralisering + +I don't want to depend on something which I cannot control. + +I don't want to depend on something which I cannot influence. + + +depend on: ++ data durability ++ privacy + +I like to follow this rule: When I create something substantial which I want to +share, I host it myself. But why? Because I don't want to depend on something +which I cannot control. + +Downside loss of social + +Requires widespread use of a decentralized social network to share private data +with a select few. + +The difficulty of leaving a service is determined by the complexity of the +social features of the service. + +I only host my own works somewhere else than on my own host if I feel that I +have a social obligation to do so, or if it's a link that points out of the +service. I don't mind if what Facebook ends up being is the new digg. + +The more difficult it is to leave a service, the more I feel I have a *social* +obligation to host my works on the service. However, the more difficult it is to +leave a service, the more I also feel that I have a *moral* obligation to /not/ +host my works on the service. + +I don't wish to host substantial works, even public ones, on e.g. Facebook. Not +because Facebook gets to know them (I have made sure I don't mind them being +public), but because I use a service which I don't like, and that may fuel the +use in general, especially for my friends. As such, it doesn't matter what I +publish on the service, it will no matter what (in varying degrees) accelerate +the use of the service, which I do not want to happen. + +In general, it's a balance. I try not to make others depend on Facebook because +of me; I do that by not uploading large photo galleries to Facebook. However, +photo galleries on Facebook have quite complex features. + +Collaborative sites diff --git a/site/writings/ordfinder/index.org b/site/writings/ordfinder/index.org new file mode 100644 index 0000000..c5711ee --- /dev/null +++ b/site/writings/ordfinder/index.org @@ -0,0 +1,377 @@ +#+title: Old junk code: Word finder +#+summary: Less than perfect C code +#+license: wtfpl, unless otherwise noted +#+startup: showall +#&toc + + +* Old junk code: Word finder + +#+caption: Based on [[https://commons.wikimedia.org/wiki/File:2001-91-1_Computer,_Laptop,_Pentagon_(5891422370).jpg][this]], CC BY 2.0 +#&img;url=sadcomputer.png, float=right + +If you ever get tired of looking at your own junk code, take a look at this. + +In August 2008, when I was still learning to program in C, I created a program +"ordfinder" (eng: word finder) which, given a word and a dictionary, prints the +words from the dictionary which can be created from the letters from the given +word in any order. Incredibly, it ended up compiling and works perfectly for any +word whose length does not exceed 8 characters, although it is a bit slow. + +But why not more than 8 characters? My view of memory might have been a bit +naive back then, because the first step in my algorithm is to generate and +store all permutations of all subsequences of the given word. That is, if the +string is "me", my program stores the array `{ "m", "e", "me", "em" }` in +memory before going on to reading the dictionary and looking for matches. + +If the string is "you", the program stores `{ "y", "o", "yo", "oy", "u", "yu", +"uy", "ou", "uo", "you", "yuo", "oyu", "ouy", "uyo", "uoy" }`. + +If the string is "computer", the program stores the 109600 permutations of the +subsequences of "computer". + +If the string is "difficult", the length of 9 characters means that the program +attempts to store 986409 strings of lengths 1 to 9. That probably takes up not +more than 10 MB, so it shouldn't be a problem. However, my program seems to +store the list of words on the stack instead of in memory, so words with length +9 or above cause a stack overflow to happen. + +In any case, a word length of 10 would require about 100 MB, a word length of 11 +about 1.2 GB, a word length of 12 about 15.6 GB, and a word length of 17 (like +"inconspicuousness") about 16,5 Petabytes (16500000 GB). That's 6,5 Petabytes +*more* than [[http://archive.org/web/petabox.php][what the Internet Archive uses]] to store millions of websites, books, +video and audio. + +So perhaps neither my algorithm nor my implementation was that good. + + +* The code + +Note that this code doesn't actually compile, because of all the wrong +code. However, it did compile back in 2008 which means that either I added the +wrong code after I had compiled it, or I used an overfriendly compiler (I don't +remember which compiler it was, but it ran on Windows). I have run the old +executable with `wine`, and that works. + +It's not necesarry to know C to laugh at this code, but it helps. + +We'll start with some basic `#include`s. + +#+BEGIN_SRC c +#include +#include +#include +#include +#include +#+END_SRC + +So far, so good. Then the global variables with descriptive names. And let's +declare four strings of length 0 to be statically allocated, because we'll just +extend them later on...? + +#+BEGIN_SRC c +char os[0],s[0],r[0],t[0]; +int l,c,rc,k,sk,i,ii,iii,ri; +#+END_SRC + +The next step is to define our own version of C's builtin `strstr` function +(almost). I was used to PHP, so I wanted the same return values as PHP's +`strpos`. + +#+BEGIN_SRC c +int strpos (const char *haystack, const char *needle) { + int i; + + if (strlen (haystack) < strlen (needle)) + return -1; + + for (i = 0; i <= (strlen (haystack) - strlen(needle)); i++) { + if (!strncmp (&haystack[i], needle, strlen(needle))) + return i; + } + + return -1; +} +#+END_SRC + +Then it's time for the main function. We don't want to separate it into +auxiliary functions, because that's just ugly! + +Indentation? Too much wastes too much space. + +#+BEGIN_SRC c +int main(int argc, char *argv[]) +{ + if (argc>1) { + strcpy(os,argv[1]); + } + else { + printf("Indtast ord: "); + gets(os); + } + printf("T\x91nker...\n"); + strcpy(s,os); + for(i=0;s[i];i++) { + s[i]=tolower(s[i]); + } +#+END_SRC + +Wait, what? We use `strcpy` to copy the string `argv[1]`, which contains the +word we want to permute, into the statically allocated `os` with length 0? Or we +read a line from standard in and save in `os`? And almost the same for `s`? +That's... not good. + +At least these two lines aren't that bad. + +#+BEGIN_SRC c + l=strlen(s); + c=pow(l,l); +#+END_SRC + +But then begins the actual permutation generation logic. I have tried to +re-understand it, with no success. + +#+BEGIN_SRC c + rc=1; + i=0; + while (i-1) {k=1;} +#+END_SRC + +If ~k == 1~, something good happens. But it doesn't happen at once for some +reason. + +#+BEGIN_SRC c + ii++; + } + if (k==1) { + printf("%s\n",wrd); + fprintf(fw,"%s\n",wrd); + wc++; + } + } + } + printf("\nI alt %d ord\n",wc); + fprintf(fw,"\nI alt %d ord",wc); + fclose(fw); + fclose(f); + system("output.txt"); + } + return 0; +} +#+END_SRC + +And that's my pretty C code. + + +* The SML equivalent + +To make my inefficient algorithm a bit clearer, I have made a few SML functions +to do the same as above: + +#+BEGIN_SRC ocaml +open List + +(* Removes an element from a list. *) +fun remove x (y :: ys) = if x = y + then ys + else y :: remove x ys + +(* Tails of a list. Stolen from Haskell's Data.List. *) +fun tails [] = [[]] + | tails (xxs as (_ :: xs)) = xxs :: tails xs + +(* Non-empty subsequences of a list. Stolen from Haskell's Data.List. *) +fun nonEmptySubsequences [] = [] + | nonEmptySubsequences (x :: xs) = + let + fun f (ys, r) = ys :: (x :: ys) :: r + in + [x] :: foldr f [] (nonEmptySubsequences xs) + end + +(* All permutations of a list. *) +fun permutations [] = [[]] + | permutations xs = + let + fun subPermutations x = map (fn ys => x :: ys) (permutations (remove x xs)) + in + concat (map subPermutations xs) + end + + +(* Permutations of subsequences of a list. *) +fun subsequencePermutations xs = concat (map permutations (nonEmptySubsequences xs)) + +(* The same, but for a string. *) +fun stringSubsequencePermutations s = map implode (subsequencePermutations (explode s)) + +(* Finds words in `wordList` which matches any permutation of any subsequence + * of `word`. *) +fun findMatchingWords word wordList = + let + val wordPermutations = stringSubsequencePermutations word + in + filter (fn testWord => + exists (fn word => word = testWord) + wordPermutations) wordList + end +#+END_SRC + +As well as some SML functions to calculate the number of permutations and bytes: + +#+BEGIN_SRC ocaml +(* Calculates the factorial. *) +fun factorial 0 = 1 + | factorial n = n * factorial (n - 1) + +(* Calculates the binomial coeffecient. *) +fun binomc n k = factorial n div (factorial k * factorial (n - k)) + +(* Gives [m, m + 1, ..., n]. *) +fun upTo m n = if m < n + then m :: upTo (m + 1) n + else [m] + +(* Gives the total number of word subsequence permutations for a given word + * length. *) +fun nPermutations len = foldl op+ 0 (map (fn n => factorial n * binomc len n) + (upTo 1 len)) + +(* Gives the size in bytes for storing all word subsequence permutations for a + * given word length in a space-saving way: there are `len` arrays, each taking + * up space for the pointer to the array and the permutations of subsequences of + * length n where `1 <= n <= len` and n is unique. + *) +fun nSize len = 8 * len + foldl op+ 0 ( + map (fn n => (n + 1) * factorial n * binomc len n) + (upTo 1 len)) +#+END_SRC + +* The alternative + +Preprocess the dictionary into a clever data structure and don't use up all the +memory. + + +#&line + +Originally published [[http://dikutal.dk/artikler/old-junk-code-word-finder][here]]. diff --git a/site/writings/ordfinder/sadcomputer.png b/site/writings/ordfinder/sadcomputer.png new file mode 100644 index 0000000..1351b9d Binary files /dev/null and b/site/writings/ordfinder/sadcomputer.png differ diff --git a/site/writings/sound-programming/index.org b/site/writings/sound-programming/index.org new file mode 100644 index 0000000..5c659a8 --- /dev/null +++ b/site/writings/sound-programming/index.org @@ -0,0 +1,291 @@ +#+title: Sound Programming +#+summary: Programming sound in Live-Sequencer and ChucK +#+license: wtfpl, unless otherwise noted +#+startup: showall +#&toc + +Much can be programmed, and that includes sound. In the digital world, sound is +typically represented by sequences of about 90 kB per second, so "printing" +sound is merely a matter of printing bytes. As such, any general purpose +language can be used to generate sounds. + +However, it's boring to create a program that does nothing but print bytes, and +it's potentially difficult to make those bytes sound nice; we want abstractions +to simplify matters for us: instruments, drums, musical notes, and a high-level +program structure. Many programming languages have good libraries that allow us +to achieve just that, but to keep it simple we'll focus on how to program sound +in two languages designed to output sound: ChucK and Live-Sequencer. + +Let's create some sounds. + + +* The square wave + +We'll start with ChucK and a small square wave program: + +#+BEGIN_SRC c +// Connect a square oscillator to the sound card. +SqrOsc s => dac; + +// Set its frequency to 440 Hz. +440 => s.freq; + +// Lower the volume. +0.1 => s.gain; + +// Let it run indefinitely. +while (true) { + 1000::second => now; +} +#+END_SRC + +ChucK is an imperative language. Instructions on how to install and run it can +be found on its [[http://chuck.cs.princeton.edu/][website]], along with other useful information. You can listen to +the above sound [[square.flac][here]]. + +To do the same in Live-Sequencer, we must find a square wave "instrument" and use +that. + +#+BEGIN_SRC haskell +module SquareWave where + +-- Basic imports. +import Prelude +import List +import Midi +import Instrument +import Pitch + +-- The function "main" is run when the program is run. + -- It returns a list of MIDI actions. +main = concat [ program lead1Square -- Use a square wave instrument. + , cycle ( -- Keep playing the following forever. + note 1000000 (a 4) -- Play 1000000 milliseconds of the musical note A4 + ) -- about 440 Hz. + ]; -- End with a semicolon. +#+END_SRC + +Live-Sequencer differs from ChucK in that it is functional, but another major +difference is that while ChucK (in general) generates raw sound bytes, +Live-Sequencer generates so-called MIDI codes, which another program converts to +the actual audio. Live-Sequencer has a couple of funky features such as +highlighting which part of one's program is played; read about it and how to +install and run it at [[http://www.haskell.org/haskellwiki/Live-Sequencer][this wiki]]. You can listen to the above sound [[squarewave.flac][here]]. + + +* Something more advanced + +Let's try to create a small piece of music which can be expressed easily in +Live-Sequencer (listen [[melodyexample.flac][here]]): + +#+BEGIN_SRC haskell +module MelodyExample where + +import Prelude +import List +import Midi +import Instrument +import Pitch + +-- Durations (in milliseconds). +en = 100; +qn = 2 * en; +hn = 2 * qn; +wn = 2 * hn; + +twice x = concat [x, x]; + +main = cycle rpgMusic; + +rpgMusic = concat [ partA g + , [Wait hn] + , twice (partB [b, d]) + , partB [a, c] + , partA b + ]; + +partA t = concat [ program frenchHorn + , mel2 c e 4 + , mel2 c e 5 -- The '=:=' operator merges two lists of actions + =:= -- so that they begin simultaneously. + (concat [ [Wait wn] + , mel2 d t 3 + ]) + ]; + +partB firsts = concat [ program trumpet + , concat (map mel0 [c, e]) + =:= + mergeMany (map mel1 firsts) + ]; + +-- Instrument-independent melodies. +mel0 x = concat [ note wn (x 3) + , note hn (x 4) + , note en (x 2) + , [Wait wn] + , twice (note qn (x 2)) + ]; + +mel1 x = concat [ note (wn + hn) (x 5) + , note (hn + qn) (x 4) + ]; + +mel2 x y n = concat [ twice (note qn (x 3)) + , concatMap (note hn . y) [3, 4, 4] + , note wn (x n) =:= note wn (y n) + ]; +#+END_SRC + +When you play the program from the Live-Sequencer GUI, the code in use is +highlighted: + +#&img;url=sound-highlight.png, width=640, center, caption=Highlighting of sound, screenshot + +The same could be expressed in ChucK, but the comparison wouldn't be fair. While +Live-Sequencer is designed for describing melodies, ChucK's purpose is sound +synthesis, which is more general. We'll create something more fitting of ChucK's +capabilities, while still focusing on the use of instruments (listen [[more_advanced.flac][here]]): + +#+BEGIN_SRC c +// Background music for an old sci-fi horror B movie. + +// Filters. +Gain g; +NRev reverb; + +// Connect the Gain to the sound card. +g => dac; + +// Connect the data sent to the sound card through the reverb filter back to the +// sound card. +adc => reverb => dac; + +// Instruments. +Mandolin mandolin; +0.2 => mandolin.gain; +Sitar sitar; +0.8 => sitar.gain; +Moog moog; + +// Instrument connections to the Gain. +mandolin => g; +sitar => g; +moog => reverb => g; + +// Play a frequency 'freq' for duration 'dura' on instrument 'inst'. +fun void playFreq(StkInstrument inst, dur dura, int freq) { + freq => inst.freq; // Set the frequency. + 0.1 => inst.noteOn; // Start playing with a velocity of 0.1. + dura => now; + 0.1 => inst.noteOff; // Stop playing. +} + +// Play a melody. +fun void a_melody(StkInstrument inst, int freq_offset) { + int i; + + // Fork the command to play "in the background". + spork ~ playFreq(moog, 600::ms, 400 - freq_offset); + + for (0 => i; i < 3; i++) { + playFreq(inst, 200::ms, 220 + freq_offset + 10 * i); + } + + // Create an array and use every element in it. + [3, 4, 4, 5, 3] @=> int ns[]; + for (0 => i; i < ns.cap(); i++) + { + playFreq(inst, 100::ms, ns[i] * 132 + freq_offset); + } +} + +// Infinite sound loop of pseudo-random frequencies. +while (true) { + spork ~ a_melody(moog, Math.random2(0, 30)); + Math.random2f(0.4, 0.9) => g.gain; // Adjust the gain. + a_melody(mandolin, Math.random2(0, 350)); + a_melody(sitar, Math.random2(200, 360)); +} +#+END_SRC + + +* Algorithmic composition + +Why not have the computer generate the melody as well as the sound? That +*sounds* like a great idea! + +Enter [[https: / / en.wikipedia.org / wiki / L-system][L-systems]]. An L-system has an alphabet and a set of rules, where each rule +is used to transform the symbol on the left-hand side to the sequence of symbols +on the right-hand side. We'll use this L-system to generate music: + +#+BEGIN_SRC c +-- Based on https://en.wikipedia.org/wiki/L-system#Example_7:_Fractal_plant +Alphabet: X, F, A, B, P, M +Rules: + X -> FMAAXBPXBPFAPFXBMX + F -> FF +#+END_SRC + +If we evaluate a L-system on a list, the system's rules are applied to each +element in the list, and results are concatenated to make a new list. If we +assign each symbol to a sequence of sounds and run the L-system a few times, we +get [[lsystem.flac][this]]. + +#+BEGIN_SRC haskell +module LSystem where + +import Prelude +import List +import Midi +import Instrument +import Pitch + +en = 100; +qn = 2 * en; +hn = 2 * qn; +wn = 2 * hn; + +-- Define the L-System. +data Alphabet = X | F | A | B | P | M; +expand X = [F, M, A, A, X, B, P, X, B, P, F, A, P, F, X, B, M, X]; +expand F = [F, F]; +expand _ = []; + +-- Map different instruments to different channels. +channelInsts = concat [ channel 0 (program celesta) + , channel 1 (program ocarina) + , channel 2 (program sitar) + ]; + +-- Define the mappings between alphabet and audio. +interpret X = [Wait hn]; +interpret F = channel 0 (note qn (c 4)); +interpret A = channel 1 (note qn (a 5)); +interpret B = channel 1 (note qn (f 5)); +interpret P = channel 2 (note hn (a 3)); +interpret M = channel 2 (note hn (f 3)); + +-- A lazily evaluated list of all iterations. +runLSystem expand xs = xs : runLSystem expand (concatMap expand xs); + +-- The sound from a L-System. +getLSystemSound expand interpret iterations start + = concatMap interpret (runLSystem expand start !! iterations); + +-- Use the third iteration of the L-System, and start with just X. +main = channelInsts ++ getLSystemSound expand interpret 3 [X]; +#+END_SRC + +Using an L-system is one of many ways to take composition to a high +level. L-systems can be used to generate fractals, which are nice. + + +* And so on + +Many abstractions in sound generation allow for fun sounds to happen. Interested +people might want to also take a look at e.g. [[http://haskell.cs.yale.edu/euterpea-2/][Euterpea]], [[http://puredata.info/][Pure Data]], or [[http://csounds.com/][Csound]]. + +#&line + +Originally published [[http://dikutal.dk/artikler/sound-programming][here]]. diff --git a/site/writings/sound-programming/lsystem.flac b/site/writings/sound-programming/lsystem.flac new file mode 100644 index 0000000..85f0d1c Binary files /dev/null and b/site/writings/sound-programming/lsystem.flac differ diff --git a/site/writings/sound-programming/melodyexample.flac b/site/writings/sound-programming/melodyexample.flac new file mode 100644 index 0000000..4b6a195 Binary files /dev/null and b/site/writings/sound-programming/melodyexample.flac differ diff --git a/site/writings/sound-programming/more_advanced.flac b/site/writings/sound-programming/more_advanced.flac new file mode 100644 index 0000000..bb90728 Binary files /dev/null and b/site/writings/sound-programming/more_advanced.flac differ diff --git a/site/writings/sound-programming/sound-highlight.png b/site/writings/sound-programming/sound-highlight.png new file mode 100644 index 0000000..386a874 Binary files /dev/null and b/site/writings/sound-programming/sound-highlight.png differ diff --git a/site/writings/sound-programming/square.flac b/site/writings/sound-programming/square.flac new file mode 100644 index 0000000..c28dfd8 Binary files /dev/null and b/site/writings/sound-programming/square.flac differ diff --git a/site/writings/sound-programming/squarewave.flac b/site/writings/sound-programming/squarewave.flac new file mode 100644 index 0000000..d13b8b2 Binary files /dev/null and b/site/writings/sound-programming/squarewave.flac differ