You're looking at Less Wrong's discussion board. This includes all posts, including those that haven't been promoted to the front page yet. For more information, see About Less Wrong.

gjm comments on Harry Potter and the Methods of Rationality discussion thread, part 15, chapter 84 - Less Wrong Discussion

3 Post author: FAWS 11 April 2012 03:39AM

You are viewing a comment permalink. View the original post to see all comments and the full post content.

Comments (1221)

You are viewing a single comment's thread. Show more comments above.

Comment author: gjm 12 April 2012 04:06:39PM 1 point [-]

Even without a lot of ear training, you can quite likely hear if a note is a quarter-tone out relative to its predecessors and successors.

Comment author: thescoundrel 12 April 2012 05:09:11PM 3 points [-]

Here is a quarter tone scale. While the changes are detectable right next to each other, much like sight delivers images based on pre-established patterns, so does hearing. When laid out in this fashion, you can hear the quarter tone differences- although to my ears (and I play music professionally, have spent much time in ear training, and love music theory) there are times it sounds like two of the same note is played successively. Move out of this context, into an interval jump, and while those with good relative pitch may think it sounds "pitchy", your mind fills it in to a close note- this is why singers with actual pitch problems still manage to gain a following. Most people cannot hear slightly wrong notes. However, none of this approaches the complexity of actually trying to sing a quarter tone. The amount of vocal training required to sing quarter tones at will is the work of a master musician- much like the the person who can successfully execute slight of hand at the highest level is someone who spends decades in honing their craft.

Comment author: gjm 12 April 2012 08:49:51PM 7 points [-]

I just tried some experiments and I find that if I take Brahms's lullaby (which I think is the one Eliezer means by "Lullaby and Goodnight") and flatten a couple of random notes by a quarter-tone, the effect is in most cases extremely obvious. And if I displace each individual pitch by a random amount from a quarter-tone flat to a quarter-tone sharp, then of course some notes are individually detectable as out of tune and some not but the overall effect is agonizing in a way that simply getting some notes wrong couldn't be.

I'm a pretty decent (though strictly amateur) musician and I'm sure many people wouldn't find such errors so obvious (and many would find it more painful than I do).

Anyway, I'm not sure what our argument actually is. The chapter says, in so many words, that Q. is humming notes "not just out of key for the previous phrases but sung at a pitch which does not correspond to any key" which seems to me perfectly explicit: part of what makes the humming so dreadful is that Q. is out of tune as well as humming wrong notes. And yes, the ability to sing accurate quarter-tones is rare and requires work to develop. So are lots of the abilities Q. has.

(Of course that doesn't require that the wrong notes be exactly quarter-tones.)

Python code snippet for anyone who wants to do a similar experiment (warning 1: works only on Windows; warning 2: quality of sound is Quirrell-like):

import random, time, winsound
for (p,d) in [(4,1),(5,1),(7,3),(None,1), (4,1),(5,1),(7,3),(None,1), (4,1),(7,1),(12,2),(11,2),(9,2),(9,2),(7,1),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(5,1),(11,1),(9,1),(7,2),(11,2),(12,4)]:
if p is None: time.sleep(0.2*d)
else: winsound.Beep(int(440*2**((p+1*(random.random()-0.5))/12.)), 200*d)
Comment author: ircmaxell 11 June 2012 03:20:35AM *  2 points [-]

Here's a tweak I made that I think keeps to the spirit.

import random, time, winsound
timebias = 0.2
pitchbias = 0.7
changebias = 0.75

current = [(4.,1.),(5.,1.),(7.,3.),(None,1.), (4.,1.),(5.,1.),(7.,3.),(None,1.),(4.,1.),(7.,1.),(12.,2.),(11.,2.),(9.,2.),(9.,2.),(7.,1.),(None,1.),(2.,1.),(4.,1.),(5.,3.),(None,1.),(2.,1.),(4.,1.),(5.,3.),(None,1.),(2.,1.),(5.,1.),(11.,1.),(9.,1.),(7.,2.),(11.,2.),(12.,4.)]

timeshift = 1;
while 1:
timeshift = timeshift + timeshift * random.uniform(1 - timebias, 1 + timebias)
if timeshift > 1.0 + 2.0 * timebias or timeshift < 1.0 - 2.0 * timebias:
timeshift = random.uniform(1.0 - timebias / 2.0, 1.0 + timebias / 2.0)
key = random.randrange(0, len(current) - 1)
if random.random() > changebias:
if current[key][0] is not None:
current[key] = (current[key][0] + current[key][0] * random.uniform(-1.0 * pitchbias, pitchbias), current[key][1])
else:
current[key] = (current[key][0], current[key][1] + current[key][1] * random.uniform( -1.0 * timebias, timebias))
time.sleep(random.random())
for (p,d) in current:
if p is None: time.sleep(0.2*d * timeshift)
else: winsound.Beep(int(440*2**(p/12.)), int(200*d*timeshift))

Basically, each loop it tweaks the song slightly from the one before it, randomly. The three different bias settings on the top dictate how the song evolves. But besides just changing the song, the rate of any play varies randomly (according to the timebias as well).

The timebias applies to changes of timing. So the tempo of the play, the rate of change of the length of a note and the length of pauses are all shifted by the timebias randomly. increasing this number will create more dramatic swings in time changes from run to run (as well as the overall bounds of the tempo).

The pitchbias applies to pitch changes. Increasing it will let the algorithm drift from the normal song much faster. Too high will cause obvious swings in notes. Too low, and it'll take forever to get a decently maddening change (but perhaps that's part of the master plan).

The changebias indicates the chance that on a particular loop, the pitch of a random note will change, or if the duration will change. This change is carried on to all future plays (and will have a ripple effect)

The result is quite maddening, as parts of the song will randomly trend back towards the correct notes. And notes you could have sworn were wrong will appear normal later. And back and forth it goes. Just repeating, and changing until you get driven mad (or bored) enough to ^C...

Basically, it's a genetic algorithm without a binding fitness function. Its random changes will just propegate infinitely towards chaos. But for a very long time it will have the "feel" of the original song...

Comment author: Schroedingers_hat 25 April 2012 05:39:44PM *  2 points [-]

I couldn't help myself. I had to have a go at making it, too.
http://jsfiddle.net/GVTk2/

Didn't check it on anything other than chromium, and I can't guarantee it won't eventually use all your memory and crash.
It's horrible in many ways: switches key, misses the frequency of notes, changes from 2^(1/12) ratio between semitones, pauses at random and changes note length.

Take a listen, there's always a chance it'll stop :D

/edit ambiguity. Come to think of it, skipping notes is the one thing I didn't do. Note that it starts reasonably close to being in tune and slowly degrades.

Comment author: LauralH 08 February 2013 01:06:54AM 0 points [-]

This is pretty awesomely horrible, all right! ::applause::

Comment author: David_Gerard 12 April 2012 09:48:19PM 1 point [-]

I can't get this to work in Wine. Could you please put up a recording? Thank you :-)

Comment author: gjm 12 April 2012 11:04:44PM 10 points [-]

Try this instead; it should work on any OS and generate a .wav file you can play. (It's better than putting up a recording because you can play with the parameters, put in your own tune, etc.)

import math, random, struct, wave
from math import sin,cos,exp,pi
filename = '/home/dgerard/something.wav' # replace with something sensible
def add_note(t,p,d,v):
# t is time in seconds, p is pitch in Hz, d is duration in seconds
# v is volume in arbitrary (amplitude) units
i0 = int(44100*t)
i1 = int(44100*(t+d))
if len(signal)<i1: signal.extend([0 for i in range(len(signal),i1)])
for i in range(i0,i1):
dt = i/44100.-t
if dt<0.02: f = dt/0.02 # attack: 0..1 over 20ms
elif dt<0.2: f = exp(-(dt-0.02)/0.18) # decay: 1..1/e over 180ms
elif dt<d-0.2: f = exp(-1) # sustain: 1/e
else: f = exp(-1)*(d-dt)/0.2 # release: 1/e..0 over 200ms
signal[i] += f*v*(sin(2*pi*p*dt)+0.2*sin(6*pi*p*dt)+0.06*sin(10*pi*p*dt))
def save_signal():
m = max(abs(x) for x in signal)
d = [int(30000./m*x) for x in signal]
w = wave.open(filename, "wb")
w.setparams((1,2,44100,len(signal),'NONE','noncompressed'))
w.writeframes(''.join(struct.pack('h',x) for x in d))
w.close()
signal = []
t=0
for (p,d) in [(4,1),(5,1),(7,3),(None,1), (4,1),(5,1),(7,3),(None,1), (4,1),(7,1),(12,2),(11,2),(9,2),(9,2),(7,1),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(5,1),(11,1),(9,1),(7,2),(11,2),(12,4)]:
if p is not None: add_note(t, 440*2**((p+1*(random.random()-0.5))/12.), 0.3*d+0.1, 1)
t += 0.3*d
save_signal()
Comment author: gjm 12 April 2012 11:19:15PM *  5 points [-]

This is quite Quirrellicious:

signal = []
t=0
for (p,d) in [(4,1),(5,1),(7,3),(None,1), (4,1),(5,1),(7,3),(None,1), (4,1),(7,1),(12,2),(11,2),(9,2),(9,2),(7,1),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1),(5,1),(11,1),(9,1),(7,2),(11,2),(12,4)]:
if p is not None: add_note(t, 440*2**(((p+random.choice([-1,0,0,0,1]))+random.random())/12.), 0.3*d+0.1, 1)
t += 0.3*d*math.exp(random.random()*random.random())
save_signal()

It (1) displaces 20% of notes up and 20% of notes down by one semitone, (2) detunes all notes randomly by about +/- a quarter-tone, and (3) inserts random delays, usually quite short but up to a factor of about 1.7 times the length of the preceding note or rest.

[EDITED to add: actually, I think it distorts the pitches just a little too much.]

[FURTHER EDITED: really, it should be tweaked so that when two consecutive notes in the original melody are, say, increasing in pitch, the same is true of the distorted ones. I am too lazy to make this happen. A simpler improvement is to replace the two pitch-diddlings with a single call to random.choice() so that you never get, e.g., a semitone displacement plus a quarter-tone mistuning in the same direction. I also tried making the timbre nastier by putting the partials at non-harmonic frequencies, which does indeed sound quite nasty but not in a particularly hummable way. This doesn't introduce as much nastiness as it would in music with actual harmony in it; one can make even a perfect fifth sound hideously discordant by messing up the spectrum of the notes. See William Sethares's excellent book "Tuning, timbre, spectrum, scale" for more details, though he inexplicably gives more attention to making music sound better rather than worse.]

Comment author: [deleted] 13 April 2012 12:37:39AM *  2 points [-]

For further fun, get the code to play the lullaby, wait an exponentially distributed time with mean, say, 30 seconds, and then start again with 99% probability.

If you were using this on someone else, starting again would be mandatory. But the only way to build up hope that it will stop in yourself, when you know how the code works, is to add a small chance of stopping.

Edit: upon further consideration, the distribution should be Pareto or something with a similarly heavy tail.

Comment author: Alsadius 13 April 2012 03:43:19AM 1 point [-]

Please post a recording, for those of us who don't want to have to set up whole programming environments to watch a Youtube video.

Comment author: fgenj 16 April 2012 02:50:58AM 4 points [-]

I've made a recording with SuperCollider using almost the same algorithm as in the Python script above, here's the link /watch?v=wjZRM6KgGbE.

Comment author: Alsadius 16 April 2012 03:32:56AM 1 point [-]

It loses much of the impact when you intentionally seek it out, I think. The lullaby loop midi I found to be more annoying than the errors.

Still, thanks for posting that - it's certainly interesting.

Comment author: Percent_Carbon 16 April 2012 06:24:46AM 1 point [-]

It loses much of the impact when you intentionally seek it out, I think.

Listening to something is not at all the same as listening to something for seven hours.

Comment author: fgenj 16 April 2012 07:45:41PM 0 points [-]

Personally, I find random changes a little disorienting even if I'm expecting them (like a deceptive cadence in a familiar piece). Though this feeling of disorientation is not unpleasant, so a simple loop would be more annoying for me too.

Comment author: zerker2000 23 January 2013 10:17:03AM 0 points [-]

"unavailable": what gives?

Comment author: Incorrect 13 April 2012 12:50:33AM *  1 point [-]

Oh well, I guess bad music isn't actually so annoying... I tried it and it didn't bother me at all.

Comment author: gjm 13 April 2012 01:30:31AM 0 points [-]

Apparently I'm not quite as good at tormenting people as Lord Voldemort. Oh well, can't win 'em all.

Comment author: 75th 12 April 2012 11:20:03PM 0 points [-]

Whooo, that is awesome.

Comment author: David_Gerard 12 April 2012 11:17:35PM 0 points [-]

So simple, and yet so awful ... you're onto sheer antimusical gold here.

Comment author: thomblake 12 April 2012 11:09:46PM 0 points [-]

Awesome. Is this your creation?

Comment author: gjm 12 April 2012 11:23:05PM 2 points [-]

I'm not sure that the word "creation" is quite right (except in so far as for some musically-minded people it may bring to mind the other words "representation of chaos") but yes, I'm afraid it is.

Comment author: gjm 12 April 2012 08:58:12PM 1 point [-]

Just to add: (1) The pointless "1*" is because I experimented with other sizes of error too. (2) A slight modification of this lets you, e.g., have the pitch drift downward by 1/10 of a semitone per note, which for me at least is very noticeable and unpleasant even though each individual interval is OK.

Comment author: mbrigdan 29 April 2012 12:24:21AM 0 points [-]

While all of the evil credit of course goes to you, I feel that I have made some neat* modifications:

signal = []
t=0L
pscale=5
pexp=2
transpose = 0
iterations = 10
for ii in range(1,iterations):
for (p,d) in [(4,1),(5,1),(7,3),(None,1), (4,1),(5,1),(7,3),(None,1), (4,1),(7,1),(12,2),(11,2),(9,2),(9,2),(7,1),(None,1), (2,1),(4,1),(5,3),(None,1), (2,1), (4,1),(5,3),(None,1), (2,1),(5,1),(11,1),(9,1),(7,2),(11,2),(12,4)]:
if p is not None: add_note(t, random.choice([440*2**(((p+transpose)+random.choice([-1,0,0,0,1]))/12.),440*2**(((p+transpose)+random.random())/12.)]), 0.3*d+0.1, 1)
t += 0.3*d*math.exp(random.random()*random.random())
transpose = random.choice([-14, -9, -7, -4.5, -2, -1, 0, 0.5, 1, 2, 4.5, 7, 9, 14]) #transpose up or down
t += 5*(pexp*((pscale**pexp)/((random.randrange(200,600,1)/100)**(pexp+1)))) #wait a while before repeating
save_signal()

*Where neat is, of course, a synonym for evil