Made by Oliver Postgate and Peter Firmin of Smallfilms, the Clangers was one of the children's TV shows that warped the largest number of small British minds.

The Clangers films were first shown in 1969, the year man landed on the moon. They were described by a NASA scientist as an attempt to bring a note of realism to the fantasy of the Space Race.".

The charmingly surreal series concerns the daily life and adventures of the Clangers--a race of highly civilised, small, bright pink, long-nosed mouse type people who stand upright on oversized feet. They talk in a high pitched whistling language that makes perfect sense to you until the tragic day on which you hit puberty.

They have large animated ears that they pull over their eyes when are sad or distressed.

The Clangers live inside a small blue cratered planet (with the craters covered with metal lids) inside which they hide from the cold and the plethora of objects falling from space.

Other inhabitants include the Soup Dragon, who lives in the soup well and who provides the Clangers with green soup and blue-string pudding; the Glow Buzzers which provide light for the Clangers' caves and tasty Glow Honey for the Clangers' pantry; the conjuring froglets, inexplicably strange sideways orange, oval stick-legged creatures which travel in a top hat and live in a vertical pond deep within the planet; and the skilled inventor the Iron Chicken.

p.s. until I was given a video of the Clangers a few years ago, I was convinced that the show was made in black and white. Discovering the extreme pinkness of the little beasts was a shock from which I have still not quite recovered.

According to Oliver Postgate, the voices are created by speaking the script through a slide whistle as it was played. The BBC insisted on script changes because the original version of the text was just too rude and sweary. That said, the squeezable talking clanger dolls do say, "Oh, bugger. The bloody door's stuck again." Allegedly.

A while back, I discovered The Clangers. I was strangely turned on by their voices.

Months later, I fired up Cool Edit and played with the "Ringing A's" filter a while, eventually isolating one 'A' and moving it up to 1000 Hz. It reminded me of Morse code in a heavy echo chamber. I brought out the Morse aspect by gating the signal at approximately the average volume. Then I realized that an easier way to generate the envelope would be to apply a heavy low-pass filter to noise and cut out the negative strokes.

  1. noise(20 s)
  2. sci_filter(butterworth lowpass 10 Hz order 6)
  3. distort(splines, positive place point at -30 dB -> 0 dB, negative to silence)
  4. AM with tones(500 Hz sine)
  5. pitchbender(squirrely)

I felt turned on in the same way.

Hours later, it hit me: that's the voice of The Clangers! I changed a few of the parameters and implemented the filter chain in straight C, using a cheesy way to generate low-pass noise with a cubic filter.


/* clangers.c
Simulate the voice of The Clangers.

Copyright 2001 Damian Yerrick (hereinafter $OWNER)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
INFRINGEMENT. IN NO EVENT SHALL $OWNER BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of $OWNER shall not be
used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from
$OWNER.

*/




#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

/* This is a template for a Canonical WAVE header.
Byte values that must be replaced are at offset
4: size of wave data + 36
22: number of channels
24: sample rate in Hz
28: avg bytes per second = sample rate * bytes per frame
32: bytes per frame = (bits per sample + 7) / 8 * channels
34: bits per sample
40: number of bytes (must be even)

Documentation at http://www.lightlink.com/tjweber/StripWav/WAVE.html
*/

const unsigned char canonical_wav_header[44] =
{
'R','I','F','F', 0, 0, 0, 0,'W','A','V','E','f','m','t',' ',
16, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,'d','a','t','a', 0, 0, 0, 0
};

void fill_32(unsigned char *dest, unsigned long src)
{
int i;

for(i = 0; i < 3; i++)
{
*dest++ = src;
src >>= 8;
}
}

typedef struct UPSAMPLE
{
float xnm3, xnm2, xnm1, xn;
float t;
float freq;
float a, b, c, d;
} UPSAMPLE;


/* upsample() **************************
Upsamples a signal using cubic spline interpolation.
Uses new_sample once every time up->t >= 1.
*/
float upsample(UPSAMPLE *up, float new_sample)
{
float tf = up->t;
float ns, omtf;

if(tf >= 1.0)
{
tf -= 1.0;
up->xnm3 = up->xnm2;

up->xnm2 = up->xnm1;
up->xnm1 = up->xn;
up->xn = new_sample;
up->a = up->xnm2;
up->d = up->xnm1;
up->b = 3 * up->a + (up->d - up->xnm3) / 2;
up->c = 3 * up->d + (up->a - up->xn) / 2;
}

omtf = 1 - tf;
ns = ((up->a*omtf+up->b*tf)*omtf*omtf + (up->c*omtf+up->d*tf)*tf*tf);

up->t = tf + up->freq;

return ns;
}


/* init_upsample() *********************
Initialize an upsample buffer.
*/
void init_upsample(UPSAMPLE *up, float freq)
{
up->freq = freq;
up->a = up->b = up->c = up->d = up->xnm2 = up->xnm1 = up->xn = 0;
up->t = 1;
}



#define OUT_FREQ (44100)
#define LEN (2560000)
#define SRC_PERIOD (OUT_FREQ / 65.625)
#define SRC_OFFSET 100
#define BYTES_PER_SAMPLE 2
#define SINMASK 0x3ff

float sintable[SINMASK + 1];

int main(void)
{
unsigned char header[44];
int cur_sample;
FILE *fp;
float yn;
UPSAMPLE keynoise = {0}, prosody = {0};
unsigned int n;

float carrier_t = 0;


/* create wav file */
memcpy(header, canonical_wav_header, 44);
fill_32(header + 4, LEN * BYTES_PER_SAMPLE + 44);

header[22] = 1;
fill_32(header + 24, OUT_FREQ);
header[32] = BYTES_PER_SAMPLE;

fill_32(header + 28, header[32] * OUT_FREQ);
header[34] = 8 * BYTES_PER_SAMPLE;
fill_32(header + 40, LEN * BYTES_PER_SAMPLE);

srand(time(NULL));
fp = fopen("168out.wav", "wb");
if(!fp)
{
perror("could not open 168out.wav");
return 1;
}
fwrite(header, 44, 1, fp);

/* initialize sine table for frequency modulation */
for(n = 0; n <= SINMASK; n++)
sintable[n] = sin(n * (2*M_PI/(SINMASK+1)));

/* initialize 5 Hz lowpass noise generator for keypresses */
init_upsample(&keynoise, 10./44100);
/* initialize 1 Hz lowpass noise generator for inflection */
init_upsample(&prosody, 2./44100);

for(n = 0; n < LEN; n++)
{
/* generate noise */
if(keynoise.t >= 1.0)
yn = upsample(&keynoise, rand() % 240 - 120);
else
yn = upsample(&keynoise, 0);

/* distort into keypresses */
if(yn < 0)
yn = 0;
else if(yn < 8)
yn = yn * yn;
else
yn = 64 + (yn - 8) / 2;

/* modulate with carrier */
yn *= sintable[(int)floor(carrier_t) & SINMASK];

/* generate noise and modulate the carrier's frequency */
if(prosody.t >= 1.0)
carrier_t += upsample(&prosody, rand() % 12 + 10);
else
carrier_t += upsample(&prosody, 0);

if(carrier_t >= 1024)
carrier_t -= 1024;
else if(carrier_t < 0)
carrier_t += 1024;

if(yn > 127)
yn = 127;
else if(yn < -127)
yn = -127;
cur_sample = yn * 256;
fputc(cur_sample & 0xff, fp);
fputc(cur_sample >> 8, fp);
}

fclose(fp);

return 0;
}
A possible improvement would be to simulate a real slide whistle with a resonant filter.

Log in or register to write something here or to contact authors.