~amavect/music

076df55e8be9dd14695588d354630199a044e6a7 — amavect 2 years ago
reorganize
23 files changed, 2204 insertions(+), 0 deletions(-)

A LICENSE
A README
A bb/0.c
A bb/1.c
A bb/10.c
A bb/11.c
A bb/12.c
A bb/2.c
A bb/4.c
A bb/5.c
A bb/6.c
A bb/7.c
A bb/8.c
A bb/9.c
A bb/mkfile
A bb/p1.c
A bb/p2.c
A bb/p3.c
A bb/p4.c
A mkfile
A piano32.c
A pianoJI.c
A xenihak.c
A  => LICENSE +19 -0
@@ 1,19 @@
Copyright (c) 2018-2020 Amavect

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 NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS 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.

A  => README +15 -0
@@ 1,15 @@
musical experiments

top level contains various programs
piano originally by umbraticus
bb/ contains bytebeat songs

build:
mk $O.$program # whatever your $O objtype prefix is

play:
# turn down your volume before playing!
6.out >/dev/audio

for piano programs:
[az] is octave, [sx] is volume, [qwertyuiop2356790] is keyboard
\ No newline at end of file

A  => bb/0.c +43 -0
@@ 1,43 @@
/* bytebeat!
 * play by writing to /dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

/* insert bytebeat formula here */
uvlong
next(uvlong t)
{
	return t;
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("%r");
	
	for(t = 0;; t++){
		x = next(t);
		y = next(t);
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("%r");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("%r");
	}
}

A  => bb/1.c +45 -0
@@ 1,45 @@
/* bytebeat!
 * play by writing to /dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

/* insert bytebeat formula here */
uvlong
next(uvlong t)
{
	t = t * 8000 / 44100;
	t = t*(42&t>>10);
	return t<<8;
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("%r");
	
	for(t = 0;; t++){
		x = next(t);
		y = next(t);
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("%r");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("%r");
	}
}

A  => bb/10.c +42 -0
@@ 1,42 @@
/* orig by pete */
/* 44.1 kHz, stereo, signed 16-bit */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

uvlong
next(uvlong t)
{
	t = t<<2; return (t-(t^((t+0xFFFF)>>1)));
	//return (128*t * ((1<<5)-((t>>9)%(1<<5)))/(1<<4));
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 1;; t++){
		x = next(t);
		y = x;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/11.c +41 -0
@@ 1,41 @@
/* orig by pete */
/* 44.1 kHz, stereo, signed 16-bit */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

uvlong
next(uvlong t)
{
	return ((t|(((t^(t>>1))&(((t>>13)%256)^((t>>18)^451)))*((t>>10)&(((t>>12)&253)^(353^(t*17)))))) ^((t>>6)&((t-(t^(t>>1)))^((t-(t^(t>>1)))<<1)^((t-(t^(t>>1)))>>1))));
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 1;; t++){
		x = next(t);
		y = x;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/12.c +40 -0
@@ 1,40 @@
/* 44.1 kHz, stereo, signed 16-bit */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

uvlong
next(uvlong t)
{
	return ((((t<<3)-(t<<3^(((t<<3)+0xFFFF)>>1))) | ((((t<<3)|(t<<2)|(t<<1)) ))) + ( ((t*t*t)/(t%256 + 1))|( (((t<<1) + (1<<15))|(t<<2)|(t<<3)|(t<<4)) ) )) ^ ((t|(((t^(t>>1))&(((t>>13)%256)^((t>>18)^451)))*((t>>10)&(((t>>12)&253)^(353^(t*17)))))) ^((t>>6)&((t-(t^(t>>1)))^((t-(t^(t>>1)))<<1)^((t-(t^(t>>1)))>>1))));
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 1;; t++){
		x = next(t);
		y = x;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/2.c +45 -0
@@ 1,45 @@
/* bytebeat!
 * play by writing to /dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

/* insert bytebeat formula here */
uvlong
next(uvlong t)
{
	uvlong s;
	t = (t<<6) | ( (((t>>1)&((t>>1)+(1<<15)))|t|(t<<1)|(t<<2)|(t<<3)) & (((s>>1)&((s>>1)+(1<<15)))|s|(s<<1)|(s<<2)|(s<<3)) );
	return t;
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("%r");
	
	for(t = 0;; t++){
		x = next(t);
		y = next(t);
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("%r");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("%r");
	}
}

A  => bb/4.c +49 -0
@@ 1,49 @@
/* Amavect!
 * Spring Beat
 * to play: 6.out >/dev/audio 
 * (turn down your volume)
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

/* insert bytebeat formula here */
uvlong
next(uvlong t)
{

	uvlong hat = ( ((t*t*t)/(t%256 + 1))|( (((t<<1) + (1<<15))|(t<<2)|(t<<3)|(t<<4)) ) );
	uvlong kick = ( (128*t * ((1<<5)-((t>>9)%(1<<5)))/(1<<4))|((t<<3)|(t<<2)|(t<<1)) );
	uvlong melody = ((3*64*t&t>>7)|(4*64*t&t>>2)|(5*64*t&t>>6)|(9*64*t&t>>4));
	return (kick + hat) ^ melody;
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 0;; t++){
		x = next(t);
		y = next(t);
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/5.c +110 -0
@@ 1,110 @@
/* Amavect!
 * Panning Test
 * to play: 6.out >/dev/audio 
 * (turn down your volume)
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

typedef struct Bytebeat Bytebeat;
typedef struct Sound Sound;
typedef struct Audio Audio;

/* unsignedlonglongbeat? */
struct Bytebeat{
	uvlong l;
	uvlong r;
};

/* continuous sounds are to be modelled with precision */
struct Sound{
	double l;
	double r;
};

/* audio(3) */
struct Audio{
	short l;
	short r;
};

/* unnecessary but whatever */
Audio
bbtoaudio(Bytebeat bb)
{
	Audio a;
	a.l = (short)(bb.l&0xFFFF);
	a.r = (short)(bb.r&0xFFFF);
	return a;
}

Sound
audiotosound(Audio a)
{
	Sound s;
	s.l = (double)a.l / (1<<15); /* avoid clipping for a.l=-1<<15 */
	s.r = (double)a.r / (1<<15);
	return s;
}

Audio
soundtoaudio(Sound s)
{
	Audio a;
	a.l = (short)(s.l * (1<<15 - 1)); /* avoid clipping for s.l=1.0 */
	a.r = (short)(s.r * (1<<15 - 1));
	return a;
}

Sound
nextpan(uvlong t)
{
	Sound m;
	m.l = cos(t / 44100.0);
	m.r = sin(t / 44100.0);
	return m;
}

Sound
soundmod(Sound s, Sound m)
{
	s.l *= m.l;
	s.r *= m.r;
	return s;
}

/* insert bytebeat formula here */
Bytebeat
next(uvlong t)
{
	Bytebeat bb;
	bb.l = t<<6;
	bb.r = bb.l;
	return bb;
}

void
main(void)
{
	uvlong t;
	Bytebeat bb;
	Audio a;
	Sound s, m;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 0;; t++){
		bb = next(t);
		s = audiotosound(bbtoaudio(bb));
		m = nextpan(t);
		s = soundmod(s, m);
		a = soundtoaudio(s);
		if(Bwrite(&bfile, &a.l, sizeof(a.l)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &a.r, sizeof(a.r)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/6.c +206 -0
@@ 1,206 @@
/* Amavect!
 * Xenihak
 * to play: 6.out >/dev/audio 
 * (turn down your volume)
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

typedef struct Bytebeat Bytebeat;
typedef struct Sound Sound;
typedef struct Audio Audio;

/* unsignedlonglongbeat? */
struct Bytebeat{
	uvlong l;
	uvlong r;
};

/* continuous sounds are to be modelled with precision */
struct Sound{
	double l;
	double r;
};

/* audio(3) */
struct Audio{
	short l;
	short r;
};

/* unnecessary but whatever */
Audio
bbtoaudio(Bytebeat bb)
{
	Audio a;
	a.l = (short)(bb.l&0xFFFF);
	a.r = (short)(bb.r&0xFFFF);
	return a;
}

Sound
audiotosound(Audio a)
{
	Sound s;
	s.l = (double)a.l / (1<<15); /* avoid clipping for a.l=-1<<15 */
	s.r = (double)a.r / (1<<15);
	return s;
}

Audio
soundtoaudio(Sound s)
{
	Audio a;
	a.l = (short)(s.l * ((1<<15) - 1)); /* avoid clipping for s.l=1.0 */
	a.r = (short)(s.r * ((1<<15) - 1));
	return a;
}

Sound
nextpan(uvlong t)
{
	Sound m;
	m.l = cos(t / (2 * 44100.0));
	m.r = sin(t / (2 * 44100.0));
	return m;
}

Sound
swapchan(Sound s)
{
	double d;
	d = s.l;
	s.l = s.r;
	s.r = d;
	return s;
}

Sound
nextvol(uvlong t)
{
	Sound v;
	v.l = sin(t / 200000.0);
	v.r = v.l;
	return v;
}

Sound
nextvol2(uvlong t)
{
	Sound v;
	v.l = cos(t / 200000.0);
	v.r = v.l;
	return v;
}
Sound
soundmod(Sound s, Sound m)
{
	s.l *= m.l;
	s.r *= m.r;
	return s;
}

Sound
soundmix(Sound s, Sound t)
{
	s.l = (s.l + t.l) / 2.0;
	s.r = (s.r + t.r) / 2.0;
	return s;
}

/* insert bytebeat formula here */
Bytebeat
next(uvlong t)
{
	Bytebeat bb;
	bb.l = (7*t<<7)&(666666|t>>4) ^ ((19*t<<6)%(1<<16))|(t>>1) ^ (3*t<<9&t>>2)^ (13*t<<10&t>>3);
	bb.r = bb.l;
	return bb;
}

Bytebeat
next2(uvlong t)
{
	Bytebeat bb;
	bb.l = (17*t<<7)&(666666|t>>7) ^ (11*t<<8&t>>6) ^ (23*t<<9&t>>3);
	bb.r = bb.l;
	return bb;
}

Bytebeat
nextdrop(uvlong t)
{
	Bytebeat bb;
	uvlong u, s, p, hat, snare, kick, bass, mel;

	hat = ( ((t*t*t)/(t%256 + 1))|( (((t<<1)|(t<<2) + (1<<15))|(t<<2)|(t<<((t<<2)&(t<<3)))|(t<<4)*(t>>13&t>>12)) ) );
	u = t+(1<<14);
	s = t+(3<<13);
	p = (t*1/1)*(((t>>17)+3)%4/3) + (t*3/4)*(((t>>17)+2)%4/3) + (t*7/8)*(((t>>17)+1)%4/3) + (t*15/16)*(((t>>17)+0)%4/3);
	kick = ( (128*t * ((1<<5)-((t>>8)%(1<<5)))/(1<<4))|( (((t>>1)&((t>>1)+(1<<15)))|t|(t<<1)|(t<<2)|(t<<3)) & (((s>>1)&((s>>1)+(1<<15)))|s|(s<<1)|(s<<2)|(s<<3)) ) );
	bass = (((1000*t/1001<<6) & (1001*t/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
	snare = ( ((t<<8)%666666) ^ ((t<<5)%(1<<16) + 1) ) | ( (u&(u+(1<<15))|(u<<1)|(u<<2)|(u<<3)) );
	mel = (7*t<<7&t>>2)|(9*t<<7&t>>3)|(19*t<<6&t>>4)|(11*t<<7&t>>5);

	if(t >= 1<<20 && t < (1<<21) - (1<<17)){
		bb.l = hat;
	}else if(t >= 1<<21 && t < 1<<22){
		bb.l = (kick + snare + hat) ^ bass;
	}else if(t >= 1<<22 && t < (1<<22) + (1<<20)){
		bb.l = (snare + hat) | mel;
	}else if(t >= (1<<22) + (1<<20) && t < (3<<21) - (1<<17)){
		bb.l = hat | mel;
	}else if(t >= 3<<21 && t < (1<<23) - (1<<17)){
		bass = (((1000*p/1001<<6) & (1001*p/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
		bb.l = (kick + snare + hat) ^ bass;
	}else if(t >= (1<<23) - (1<<17) && t < 1<<23){
		bass = (((1000*p/1001<<6) & (1001*p/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
		bb.l = (snare + hat) ^ bass;
	}else{
		bb.l = 0;
	}
	bb.r = bb.l;
	return bb;
}

void
main(void)
{
	uvlong t;
	Bytebeat b1, b2, b3;
	Audio a;
	Sound s1, s2, s3, m1, m2, v1, v2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 0; t < (1<<23) + (1<<20); t++){
		b1 = next(t);
		b2 = next2(t);
		s1 = audiotosound(bbtoaudio(b1));
		s2 = audiotosound(bbtoaudio(b2));
		m1 = nextpan(t);
		m2 = swapchan(m1);
		v1 = nextvol(t);
		v2 = nextvol2(t);
		s1 = soundmod(s1, m1);
		s2 = soundmod(s2, m2);
		s1 = soundmod(s1, v1);
		s2 = soundmod(s2, v2);
		s1 = soundmix(s1, s2);
		b3 = nextdrop(t);
		s3 = audiotosound(bbtoaudio(b3));
		s3 = soundmix(s3, s1);
		s3.l *= 4.0/3.0; /* normalize, as max(s3)≈0.749999 due to panning phase */
		s3.r *= 4.0/3.0;
		a = soundtoaudio(s3);
		if(Bwrite(&bfile, &a.l, sizeof(a.l)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &a.r, sizeof(a.r)) < 0)
			sysfatal("Bwrite failed!");
	}
	
	exits(nil);
}

A  => bb/7.c +51 -0
@@ 1,51 @@
/* Amavect!
 * Collatz Conjecture
 * to play: 6.out >/dev/audio 
 * (turn down your volume)
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

/* insert bytebeat formula here */
uvlong
next(uvlong t)
{
	if(t % 2 == 0)
		return t / 2;
	else
		return 3 * t + 1;
}

void
main(void)
{
	uvlong t, u;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	u = 1;
	for(t = 1;; t = next(t)){
		if(t == 1)
			t = u++;
		x = t;
		y = t;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/8.c +46 -0
@@ 1,46 @@
/* orig by pete */
/* 44.1 kHz, stereo, signed 16-bit */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

uvlong
next(uvlong t)
{
	return ((((t>>2)&0xff)^0x99) * ((t|(t>>10))&0xff)) |
		(((t<<4)&(1|(~t)))) +
		((t + (t>>8) + (t>>16) + (t>>24)) /
		 (1|((t>>17) &
		  (((t>>((((t>>17)&0xf)^0x4)^(~(t>>12)&0xf)))%42)*0x7ff))))
	/**/;
}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 1;; t++){
		x = next(t);
		y = x;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/9.c +42 -0
@@ 1,42 @@
/* orig by pete */
/* 44.1 kHz, stereo, signed 16-bit */
#include <u.h>
#include <libc.h>
#include <bio.h>

/* unnecessary but whatever */
short
vtos(uvlong v)
{
	return (short)(v&0xFFFF);
}

uvlong
next(uvlong t)
{
	return ((t>>20)+((t<<5)|(t>>2))) |((((0x81ca)&(0x83e9e97be99393e9LL>>(4*(((t>>14)-(t>>18))%16))))*(t<<15))/44100);

}

void
main(void)
{
	uvlong t;
	uvlong x, y;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 1;; t++){
		x = next(t);
		y = x;
		s = vtos(x);
		s2 = vtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/mkfile +6 -0
@@ 1,6 @@
</$objtype/mkfile

default:V:
	echo 'usage: mk $O.0, mk $O.1, ...'

</sys/src/cmd/mkmany

A  => bb/p1.c +112 -0
@@ 1,112 @@
/* Amavect!
 * Quick PM synthesis demo.
 * echo 'master 70' >/dev/volume
 * 6.out >/dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

#define SAMPLERATE 44100
double prate = 1 / (double)SAMPLERATE; 
uvlong srate = SAMPLERATE;

short dtos(double d);

short
dtos(double d)
{
	short s;
	if(d > 1.0 || d < -1.0)
		sysfatal("no do dat pls");
	s = (short)(d*32767);
	return s;
}

double osc1t = 0.0;

double
osc1(double p, double phi, double amt)
{
	double out = cos(2*PI*(p*osc1t) + amt*phi);
	osc1t += prate;
	return out;
}

double osc2t = 0.0;

double
osc2(double p, double phi, double amt)
{
	double out = cos(2*PI*(p*osc2t) + amt*phi);
	osc2t += prate;
	return out;
}

double osc3t = 0.0;

double
osc3(double p, double phi, double amt)
{
	double out = cos(2*PI*(p*osc3t) + amt*phi);
	osc3t += prate;
	return out;
}

double env1t = 0.0;
double
env1(uchar trig)
{
	double r = 0.0;
	if(trig != 0)
		env1t = 0.0;
	if(env1t >= 3.0)
		r = 0.0;
	else if(env1t >= 0.0)
		r = 1.0-env1t/3;
	env1t += prate;
	return r;
}

double env2t = 0.0;
double
env2(uchar trig)
{
	double r = 0.0;
	if(trig != 0)
		env2t = 0.0;
	if(env2t >= 2.0)
		r = 0.0;
	else if(env2t >= 0.0)
		r = 1.0-env2t/2;
	env2t += prate;
	return r;
}

void
main(void)
{
	uvlong t;
	uchar trig;
	double x, y, amt1, amt2;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 0;; t++){
		trig = (t%(4*srate)) == 0;
		amt1 = env1(trig);
		amt2 = env2(trig);
		x = osc1(200, osc2(200,0,0)*amt2, 10000)*amt1;
		y = x;
		s = dtos(x);
		s2 = dtos(y);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
	exits(nil);
}

A  => bb/p2.c +152 -0
@@ 1,152 @@
/* Amavect!
 * More complex PM synthesis + vibrato demo.
 * Uses structs to represent Oscs and ADSR envelopes.
 * Structs and funcs could be moved to a lib.
 * don't blow your ears: echo 'master 80' >/dev/volume
 * 6.out >/dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

short dtos(double d);

/* Linear ADSR envelope */
typedef struct Adsr Adsr;
struct Adsr {
	int on; /* on/off flag */
	double t;  /* time */
	double a;  /* attack length */
	double d;  /* decay length */
	double s;  /* sustain volume, [0.0, 1.0] */
	double r;  /* release length */
	double amp; /* current amplitude */
};

/* Generic oscillator struct */
typedef struct Osc Osc;
struct Osc {
	double ω; /* pitch, in Hz */
	double θ; /* angle, in turns */
	double φ; /* phase shift, in turns */
	double (*wave)(Osc*); /* -1.0 <= wave(Osc) <= 1.0 */
	double amp; /* current amplitude */
};

enum{
	srate = 44100, /* sample rate */
	prate = 1 / (double)srate, /* period rate */
};

short
dtos(double d)
{
	short s;
	if(d > 1.0 || d < -1.0)
		sysfatal("no do dat pls");
	s = (short)(d*32767);
	return s;
}

/* not gonna prevent you from being stupid! */
Adsr
adsrnew(double a, double d, double s, double r)
{
	Adsr adsr;
	adsr.on = 0;
	adsr.a = a;
	adsr.d = d;
	adsr.s = s;
	adsr.r = r;
	adsr.t = r;
	return adsr;
}

void
adsrnext(Adsr *adsr, double Δt, int trig)
{
	double a, d, s, r;
	a = adsr->a;
	d = adsr->d;
	s = adsr->s;
	r = adsr->r;
	if(trig == 1){
		adsr->t = 0.0;
		adsr->on = adsr->on ? 0 : 1;
	}
	if(adsr->on == 1){
		if(adsr->t < a)
			adsr->amp = adsr->t / a;
		else if(adsr->t < a+d)
			adsr->amp = (1 - (1 - s)*(adsr->t - a)/d);
		else
			adsr->amp = s;
	} else{
		if(adsr->t < r)
			adsr->amp = s * (1 - adsr->t/r);
		else
			adsr->amp = 0;
	}
	adsr->t += Δt;
}

void
oscnext(Osc *osc, double Δt)
{
	osc->amp = osc->wave(osc);
	osc->θ += Δt * osc->ω;
}

double
oscsine(Osc *osc)
{
	return sin(2*PI*(osc->θ + osc->φ));
}

double
oscsaw(Osc *osc)
{
	double a = osc->θ + osc->φ;
	return a - floor(a);
}

void
main(void)
{
	uvlong t;
	uchar trig;
	Adsr env1, env2;
	Osc osc1, osc2;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	env1 = adsrnew(1,1,0.5,1);
	env2 = adsrnew(1,1,0.5,1);
	osc1.wave = oscsine;
	osc2.wave = oscsine;
	osc1.ω = 200;
	osc2.ω = 200;
	
	for(t = 0;; t++){
		trig = (t%(4*srate)) == 0;
		adsrnext(&env1, prate, trig);
		adsrnext(&env2, prate, trig);
		oscnext(&osc2, prate);
		osc2.ω = 200 + 3*sin(3*2*PI*t*prate);
		osc1.ω = 200 + 3*sin(3*2*PI*t*prate);
		osc1.φ = osc2.amp * env2.amp * 3;
		oscnext(&osc1, prate);
		
		//print("%f, %f %f %f\n", osc1.amp, osc2.amp, env1.amp, env2.amp);
		
		s = dtos(osc1.amp*env1.amp);
		s2 = dtos(osc1.amp*env1.amp);
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/p3.c +170 -0
@@ 1,170 @@
/* Amavect!
 * More complex PM synthesis + vibrato demo.
 * Uses structs to represent Oscs and ADSR envelopes.
 * Structs and funcs could be moved to a lib.
 * don't blow your ears: echo 'master 80' >/dev/volume
 * 6.out >/dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

short dtos(double d);

/* Linear ADSR envelope */
typedef struct Adsr Adsr;
struct Adsr {
	int on; /* on/off flag */
	double t;  /* time */
	double a;  /* attack length */
	double d;  /* decay length */
	double s;  /* sustain volume, [0.0, 1.0] */
	double r;  /* release length */
	double amp; /* current amplitude */
};

/* Generic oscillator struct */
typedef struct Osc Osc;
struct Osc {
	double ω; /* pitch, in Hz */
	double θ; /* angle, in turns */
	double φ; /* phase shift, in turns */
	double (*wave)(Osc*); /* -1.0 <= wave(Osc) <= 1.0 */
	double amp; /* current amplitude */
};

enum{
	srate = 44100, /* sample rate */
	prate = 1 / (double)srate, /* period rate */
};

short
dtos(double d)
{
	short s;
	if(d > 1.0 || d < -1.0)
		sysfatal("no do dat pls");
	s = (short)(d*32767);
	return s;
}

/* not gonna prevent you from being stupid! */
Adsr
adsrnew(double a, double d, double s, double r)
{
	Adsr adsr;
	adsr.on = 0;
	adsr.a = a;
	adsr.d = d;
	adsr.s = s;
	adsr.r = r;
	adsr.t = r;
	return adsr;
}

void
adsrnext(Adsr *adsr, double Δt, int trig)
{
	double a, d, s, r;
	a = adsr->a;
	d = adsr->d;
	s = adsr->s;
	r = adsr->r;
	if(trig == 1){
		adsr->t = 0.0;
		adsr->on = adsr->on ? 0 : 1;
	}
	if(adsr->on == 1){
		if(adsr->t < a)
			adsr->amp = adsr->t / a;
		else if(adsr->t < a+d)
			adsr->amp = (1 - (1 - s)*(adsr->t - a)/d);
		else
			adsr->amp = s;
	} else{
		if(adsr->t < r)
			adsr->amp = s * (1 - adsr->t/r);
		else
			adsr->amp = 0;
	}
	adsr->t += Δt;
}

void
oscnext(Osc *osc, double Δt)
{
	osc->amp = osc->wave(osc);
	osc->θ += Δt * osc->ω;
}

double
oscsine(Osc *osc)
{
	return sin(2*PI*(osc->θ + osc->φ));
}

double
oscsaw(Osc *osc)
{
	double a = osc->θ + osc->φ;
	return a - floor(a);
}

void
main(void)
{
	uvlong t;
	uint trig, trig2;
	Adsr env1, env2;
	Osc osc1, osc2, osc3, osc4, osc5, osc6;
	double mix;
	short s, s2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	env1 = adsrnew(0.05, 1.0, 0.0, 0.0);
	env2 = adsrnew(0.05, 1.0, 0.0, 0.0);
	osc1.wave = oscsaw;
	osc2.wave = oscsaw;
	osc3.wave = oscsaw;
	osc4.wave = oscsaw;
	osc5.wave = oscsaw;
	osc6.wave = oscsaw;
	osc1.ω = 302;
	osc2.ω = 298;
	osc3.ω = 300;
	osc4.ω = 452;
	osc5.ω = 448;
	osc6.ω = 450;
	
	for(t = 0;; t++){
		trig = (t%(1*srate)) == 0;
		trig2 = ((t + srate/2)%(1*srate)) == 0;
		adsrnext(&env1, prate, trig);
		adsrnext(&env2, prate, trig2);
		osc1.ω = 298 + 3*sin(3*2*PI*t*prate);
		osc2.ω = 302 + 3*sin(3*2*PI*t*prate);
		osc3.ω = 300 + 3*sin(3*2*PI*t*prate);
		osc4.ω = 452 + 3*sin(3*2*PI*t*prate);
		osc5.ω = 448 + 3*sin(3*2*PI*t*prate);
		osc6.ω = 450 + 3*sin(3*2*PI*t*prate);
		oscnext(&osc1, prate);
		oscnext(&osc2, prate);
		oscnext(&osc3, prate);
		oscnext(&osc4, prate);
		oscnext(&osc5, prate);
		oscnext(&osc6, prate);
		
		mix = (env1.amp * (osc1.amp + osc2.amp + osc3.amp)
			+ env2.amp * (osc4.amp + osc5.amp + osc6.amp)) / 6.0;
		
		s = dtos(mix);
		s2 = s;
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => bb/p4.c +260 -0
@@ 1,260 @@
/* Amavect!
 * Synth loop!!!!
 * Filters + preliminary resonance.
 * Resonance needs better control over resonant frequency.
 *   For some reason, changing resonance amount changes the resonant frequency.
 *   Thus, resfilter() needs a new algorithm.
 * don't blow your ears: echo 'master 90' >/dev/volume
 * 6.out >/dev/audio
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

short dtos(double d);

/* Linear ADSR envelope */
typedef struct Adsr Adsr;
struct Adsr {
	int on; /* on/off flag */
	double t;  /* time */
	double a;  /* attack length */
	double d;  /* decay length */
	double s;  /* sustain volume, [0.0, 1.0] */
	double r;  /* release length */
	double amp; /* current amplitude */
};

/* Generic oscillator struct */
typedef struct Osc Osc;
struct Osc {
	double ω; /* pitch, in Hz */
	double θ; /* angle, in turns */
	double φ; /* phase shift, in turns */
	double (*wave)(Osc*); /* -1.0 <= wave(Osc) <= 1.0 */
	double amp; /* current amplitude */
};

/* infinite impulse response low pass filter */
typedef struct Lpf Lpf;
struct Lpf {
	double cut; /* cutoff frequency */
	double amp; /* current amplitude */
};

/* resonator */
typedef struct Res Res;
struct Res {
	Lpf;
	double res; /* resonance */
	double Δamp; /* amplitude change */
};

enum{
	srate = 44100, /* sample rate */
	prate = 1 / (double)srate, /* period rate */
};

short
dtos(double d)
{
	short s;
	if(d > 1.0 || d < -1.0)
		sysfatal("no do dat pls");
	s = (short)(d*32767);
	return s;
}

/* not gonna prevent you from being stupid! */
Adsr
adsrnew(double a, double d, double s, double r)
{
	Adsr adsr;
	adsr.on = 0;
	adsr.a = a;
	adsr.d = d;
	adsr.s = s;
	adsr.r = r;
	adsr.t = r;
	return adsr;
}

void
adsrnext(Adsr *adsr, double Δt, int trig)
{
	double a, d, s, r;
	a = adsr->a;
	d = adsr->d;
	s = adsr->s;
	r = adsr->r;
	if(trig == 1){
		adsr->t = 0.0;
		adsr->on = adsr->on ? 0 : 1;
	}
	if(adsr->on == 1){
		if(adsr->t < a)
			adsr->amp = adsr->t / a;
		else if(adsr->t < a+d)
			adsr->amp = (1 - (1 - s)*(adsr->t - a)/d);
		else
			adsr->amp = s;
	} else{
		if(adsr->t < r)
			adsr->amp = s * (1 - adsr->t/r);
		else
			adsr->amp = 0;
	}
	adsr->t += Δt;
}

void
oscnext(Osc *osc, double Δt)
{
	osc->amp = osc->wave(osc);
	osc->θ += Δt * osc->ω;
}

double
oscsine(Osc *osc)
{
	return sin(2*PI*(osc->θ + osc->φ));
}

double
oscsaw(Osc *osc)
{
	double a = osc->θ + osc->φ;
	return a - floor(a);
}

double
oscnoise(Osc*)
{
	return frand();
}

void
lpffilter(Lpf *lpf, double in, double Δt)
{
	double rc, α;
	rc = 1 / (2 * PI * lpf->cut); /* infinity is useful! */
	α = Δt / (Δt + rc);
	lpf->amp = α * in + (1-α) * lpf->amp;
}

void
resfilter(Res *res, double in, double Δt)
{
	double rc, α;
	rc = 1 / (2 * PI * res->cut); /* infinity is useful! */
	α = Δt / (Δt + rc);
	res->Δamp += α * (in - res->amp);
	res->amp += res->res * res->Δamp + (1 - res->res) * α * (in - res->amp);
}

void
main(void)
{
	uvlong t;
	uint trig, trig2, trigkick, trighat, trigsn;
	Adsr env1, env2, env3, env4, envkick, envhat, envsn1ω, envsn1, envsn2;
	Osc osc1, osc2, osc3, osc4, osc5, osc6, lfo1, osckick, oschat, oscsn1, oscsn2;
	Lpf lpfhat, lpfsnare;
	Res rlpf1, rlpf2;
	double mix, mix1, mix2, mix3, mix4, mix5, mix6, mix7;
	short s, s2;
	Biobuf bfile;
	
	/* disable FPZDIV, allow div by 0 */
	setfcr(FPPDBL|FPRNR|FPINVAL|FPOVFL); 
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	env1 = adsrnew(0.05, 0.2, 0.0, 0.0);
	env2 = adsrnew(0.05, 0.2, 0.0, 0.0);
	env3 = adsrnew(0.05, 0.05, 0.05, 0.1);
	env4 = adsrnew(0.05, 0.05, 0.05, 0.1);
	envkick = adsrnew(0.0, 0.05, 0.0, 0.0);
	envhat = adsrnew(0.0, 0.1, 0.0, 0.0);
	envsn1ω = adsrnew(0.0, 0.05, 0.0, 0.0);
	envsn1 = adsrnew(0.0, 0.1, 0.0, 0.0);
	envsn2 = adsrnew(0.0, 0.15, 0.0, 0.0);
	osc1.wave = oscsaw;
	osc2.wave = oscsaw;
	osc3.wave = oscsaw;
	osc4.wave = oscsaw;
	osc5.wave = oscsaw;
	osc6.wave = oscsaw;
	lfo1.wave = oscsine;
	osckick.wave = oscsine;
	oschat.wave = oscnoise;
	oscsn1.wave = oscsine;
	oscsn2.wave = oscnoise;
	osc1.ω = 79.43;
	osc2.ω = 80;
	osc3.ω = 80.55;
	osc4.ω = 119.47;
	osc5.ω = 120;
	osc6.ω = 120.57;
	lfo1.ω = 0.20;
	lpfhat.cut = 5000;
	lpfsnare.cut = 800;
	rlpf1.res = 0.5;
	rlpf2.res = 0.5;
	
	for(t = 0;; t++){
		trigkick = ((t)%(srate/2)) == 0 || ((t+1)%(srate/2)) == 0;
		trighat = ((t-srate/4)%(srate/2)) == 0 || ((t-3*srate/8)%(srate/2)) == 0;
		trigsn = ((t+srate/2)%(srate)) == 0 || ((t+srate/4)%(srate)) == 0;
		trig = ((t)%(srate/2)) == 0 || ((t-srate/8+1)%(srate/2)) == 0
		|| ((t-srate/8)%(srate/2)) == 0 || ((t-srate/4+1)%(srate/2)) == 0
		|| ((t-srate/4)%(srate/2)) == 0 || ((t-3*srate/8+1)%(srate/2)) == 0;
		trig2 = ((t-3*srate/8)%(srate/2)) == 0 || ((t+1)%(srate/2)) == 0;
		adsrnext(&env1, prate, trig);
		adsrnext(&env2, prate, trig2);
		adsrnext(&env3, prate, trig);
		adsrnext(&env4, prate, trig2);
		adsrnext(&envkick, prate, trigkick);
		adsrnext(&envhat, prate, trighat);
		adsrnext(&envsn1ω, prate, trigsn);
		adsrnext(&envsn1, prate, trigsn);
		adsrnext(&envsn2, prate, trigsn);
		osckick.ω = 200 * envkick.amp + 40;
		oscsn1.ω = 100 * envsn1ω.amp + 200;
		oscnext(&osc1, prate);
		oscnext(&osc2, prate);
		oscnext(&osc3, prate);
		oscnext(&osc4, prate);
		oscnext(&osc5, prate);
		oscnext(&osc6, prate);
		oscnext(&lfo1, prate);
		oscnext(&osckick, prate);
		oscnext(&oschat, prate);
		oscnext(&oscsn1, prate);
		oscnext(&oscsn2, prate);
		rlpf1.cut = (2500 + 2000*lfo1.amp) * env3.amp + 100;
		rlpf2.cut = (2500 + 2000*lfo1.amp) * env4.amp + 100;
		
		mix1 = env1.amp * (osc1.amp + osc2.amp + osc3.amp) / 3.0;
		mix2 = env2.amp * (osc4.amp + osc5.amp + osc6.amp) / 3.0;
		mix3 = envkick.amp * osckick.amp;
		mix4 = envhat.amp * oschat.amp;
		mix5 = envsn2.amp * oscsn2.amp;
		resfilter(&rlpf1, mix1, prate);
		resfilter(&rlpf2, mix2, prate);
		lpffilter(&lpfhat, mix4, prate);
		lpffilter(&lpfsnare, mix5, prate);
		mix6 = mix4 - lpfhat.amp; /* high pass filter */
		mix7 = 0.3*envsn1.amp * oscsn1.amp + 0.7*(mix5-lpfsnare.amp);
		
		mix = (rlpf1.amp + rlpf2.amp + 0.8*mix3 + 0.6*mix6 + 0.6*mix7)/3.6;
		//mix = mix7;
		s = dtos(mix);
		s2 = s;
		if(Bwrite(&bfile, &s, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &s2, sizeof(s)) < 0)
			sysfatal("Bwrite failed!");
	}
}

A  => mkfile +5 -0
@@ 1,5 @@
</$objtype/mkfile

TARG=xenihak pianoJI piano32

</sys/src/cmd/mkmany

A  => piano32.c +239 -0
@@ 1,239 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>

enum{
	SAW = 0, TRI, SIN, SQ, WAVES,
	WAV = 128,
	RATE = 44100,
	BUF = RATE * 4 / 50,
	OCTS = 9,
	NOTES = OCTS * 12,
	SHARPS = 1354,	/* 0b010101001010 */
	WWD = 48,
	WHT = 180,
	BWD = 28,
	BHT = 120,
};

char *waveforms[] = {"sawtooth", "triangle", "sine", "square", nil};
Menu b2 = {waveforms, nil, 0};
char *name = "CCDDEFFGGAAB";
char *key = "\t1q2we4r5t6yu8i9op-[=]\b\\";
int oct = 4, vol = 63, wav[WAVES][WAV], wavn;
char on[NOTES];
u32int θ[NOTES], Δ[NOTES];
Rectangle w[14], b[10];
int woff[14] = {0,2,4,5,7,9,11,12,14,16,17,19,21,23};
int boff[10] = {1,3,6,8,10,13,15,18,20,22};
Image *down;
Rune info[128];
Point infop;

void
redraw(void)
{
	int i;
	Rune *r;

	draw(screen, screen->r, down, nil, ZP);
	for(i = 0; i < nelem(w); i++){
		draw(screen, w[i], on[12*oct+woff[i]]?down:display->white, nil, ZP);
		border(screen, w[i], 1, display->black, ZP);
	}
	for(i = 0; i < nelem(b); i++){
		draw(screen, b[i], on[12*oct+boff[i]]?down:display->black, nil, ZP);
		border(screen, b[i], 1, display->black, ZP);
	}
	for(i = 0, r = info; i < oct; i++)
		*r++ = '-';
	*r++ = '0' + i++;
	*r++ = '0' + i;
	while(++i < OCTS)
		*r++ = '-';
	*r++ = ' ';
	for(i = 0; i < NOTES; i++)
		if(on[i]){
			*r++ = name[i % 12];
			if(SHARPS & 1 << i % 12)
				*r++ = 0x266e;	/* ♮ */
			*r++ = i / 12 + '0';
			*r++ = ' ';
			if(r - info > nelem(info) - 5)
				break;
		}
	*r = '\0';
	runestring(screen, infop, display->black, ZP, font, info);
	flushimage(display, 1);
}

void
rthread(void *arg)
{
	Mousectl *m;
	Point p;
	int fd, i;

	for(m = arg;;){
		recvul(m->resizec);
		if(getwindow(display, Refnone) < 0)
			sysfatal("getwindow: %r");
		if((Dx(screen->r) != nelem(w) * WWD
		 || Dy(screen->r) != WHT + font->height)
		&&(fd = open("/dev/wctl", OWRITE)) >= 0){
			fprint(fd, "resize -dx %d -dy %d",
				nelem(w) * WWD + 2 * Borderwidth,
				WHT + font->height + 2 * Borderwidth);
			close(fd);
		}
		for(i = 0, p = screen->r.min; i < nelem(w); i++, p.x += WWD)
			w[i] = rectaddpt(Rect(0, 0, WWD, WHT), p);
		for(i = nelem(b), p.x -= WWD + BWD / 2; i--; p.x -= WWD){
			b[i] = rectaddpt(Rect(0, 0, BWD, BHT), p);
			if(i % 5 == 0 || i % 5 == 2)
				p.x -= WWD;
		}
		infop = Pt(screen->r.min.x, screen->r.max.y - font->height);
		redraw();
	}
}

void
mthread(void *arg)
{
	Mousectl *m;
	int i;

	for(m = arg;;){
		recv(m->c, m);
		switch(m->buttons){
		default:
			continue;
		case 1:
			for(i = 0; i < nelem(b); i++)
				if(ptinrect(m->xy, b[i])){
					on[oct*12+boff[i]] |= 2;
					goto draw;
				}
			for(i = 0; i < nelem(w); i++)
				if(ptinrect(m->xy, w[i])){
					on[oct*12+woff[i]] |= 2;
					break;
				}
			break;
		case 2:
			i = menuhit(2, m, &b2, nil);
			if(i >= 0 && i < WAVES)
				wavn = i;
			break;
		case 4:
			for(i = 0; i < nelem(b); i++)
				if(ptinrect(m->xy, b[i])){
					on[oct*12+boff[i]] &= 1;
					goto draw;
				}
			for(i = 0; i < nelem(w); i++)
				if(ptinrect(m->xy, w[i])){
					on[oct*12+woff[i]] &= 1;
					break;
				}
			break;
		}
draw:		redraw();
	}
}

void
kproc(void *)
{
	int fd, n, i;
	char buf[128], *p;

	if((fd = open("/dev/kbd", OREAD)) < 0)
		sysfatal("open: %r");
	for(;;){
		if((n = read(fd, buf, sizeof(buf) - 1)) < 0)
			sysfatal("read: %r");
		buf[n] = '\0';
		for(p = buf; p - buf < n;){
			if(*p++ != 'c'){
				if(strchr(p, Kdel)){
					close(fd);
					threadexitsall(nil);
				}
				if(strchr(p, 'a') && oct < OCTS - 2)
					oct++;
				if(strchr(p, 'z') && oct)
					oct--;
				if(strchr(p, 's') && vol < 126)
					vol += 7;
				if(strchr(p, 'x') && vol > 6)
					vol -= 7;
				for(i = 0; i < strlen(key); i++){
					if(strchr(p, key[i]))
						on[12 * oct + i] |= 1;
					else
						on[12 * oct + i] &= 2;
				}
				redraw();
			}
			while(*p++)
				;
		}
	}
}

void
threadmain(int,char *argv[])
{
	Mousectl *m;
	int fd, i, s;
	uchar buf[BUF], *p;

	for(i = 0; i < WAV / 2; i++){
		wav[SAW][i] = 64 - 2 * 64 * i / WAV;
		wav[TRI][i] = 64 - 64 * i * 4 / WAV;
		wav[SIN][i] = 64 * sin(2 * PI * i / WAV);
		wav[SQ][i] = -64;
	}
	for(; i < WAV; i++){
		wav[SAW][i] = 64 - 2 * 64 * i / WAV;
		wav[TRI][i] = 64 * (i - WAV / 2) * 4 / WAV - 64;
		wav[SIN][i] = 64 * sin(2 * PI * i / WAV);
		wav[SQ][i] = 64;
	}
	for(i = 0; i < NOTES; i++)
		Δ[i] = (u32int)((440 * pow(2, 32.0)) * pow(2, (i - 57) / 12.0) / RATE);
	if((fd = open("/dev/audio", OWRITE)) < 0)
		sysfatal("open: %r");
	if(initdraw(nil, nil, argv0 = argv[0]) < 0)
		sysfatal("initdraw: %r");
	if((down = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen)) == nil)
		sysfatal("allocimage: %r");
	if((m = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if(threadcreate(rthread, m, mainstacksize) < 0)
		sysfatal("threadcreate: %r");
	if(threadcreate(mthread, m, mainstacksize) < 0)
		sysfatal("threadcreate: %r");
	if(proccreate(kproc, nil, mainstacksize) < 0)
		sysfatal("proccreate: %r");
	sendul(m->resizec, 1);
	for(;;){
		for(p = buf; p - buf < BUF; p += 4){
			for(i = 0, s = 0; i < NOTES; i++)
				if(on[i])
					s += wav[wavn][(θ[i] += Δ[i]) >> 25];
			s *= vol;
			p[0] = p[2] = s;
			p[1] = p[3] = s >> 8;
		}
		if(write(fd, buf, BUF) != BUF)
			break;
		yield();
	}
	close(fd);
}

A  => pianoJI.c +260 -0
@@ 1,260 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <thread.h>

enum{
	SAW = 0, TRI, SIN, SQ, WAVES,
	WAV = 128,
	RATE = 44100,
	BUF = RATE * 4 / 50,
	OCTS = 9,
	NOTES = OCTS * 12,
	SHARPS = 1354,	/* 0b010101001010 */
	WWD = 48,
	WHT = 180,
	BWD = 28,
	BHT = 120,
};

char *waveforms[] = {"sawtooth", "triangle", "sine", "square", nil};
Menu b2 = {waveforms, nil, 0};
char *name = "CCDDEFFGGAAB";
char *key = "\t1q2we4r5t6yu8i9op-[=]\b\\";
int oct = 4, vol = 63, wav[WAVES][WAV], wavn;
char on[NOTES];
u32int θ[NOTES], Δ[NOTES];
Rectangle w[14], b[10];
int woff[14] = {0,2,4,5,7,9,11,12,14,16,17,19,21,23};
int boff[10] = {1,3,6,8,10,13,15,18,20,22};
Image *down;
Rune info[128];
Point infop;

u32int
powu32int(u32int x, u32int y)
{
	u32int a = 1;
	for(; y > 0; y--)
		a *= x;
	return a;
}

void
redraw(void)
{
	int i;
	Rune *r;

	draw(screen, screen->r, down, nil, ZP);
	for(i = 0; i < nelem(w); i++){
		draw(screen, w[i], on[12*oct+woff[i]]?down:display->white, nil, ZP);
		border(screen, w[i], 1, display->black, ZP);
	}
	for(i = 0; i < nelem(b); i++){
		draw(screen, b[i], on[12*oct+boff[i]]?down:display->black, nil, ZP);
		border(screen, b[i], 1, display->black, ZP);
	}
	for(i = 0, r = info; i < oct; i++)
		*r++ = '-';
	*r++ = '0' + i++;
	*r++ = '0' + i;
	while(++i < OCTS)
		*r++ = '-';
	*r++ = ' ';
	for(i = 0; i < NOTES; i++)
		if(on[i]){
			*r++ = name[i % 12];
			if(SHARPS & 1 << i % 12)
				*r++ = 0x266e;	/* ♮ */
			*r++ = i / 12 + '0';
			*r++ = ' ';
			if(r - info > nelem(info) - 5)
				break;
		}
	*r = '\0';
	runestring(screen, infop, display->black, ZP, font, info);
	flushimage(display, 1);
}

void
rthread(void *arg)
{
	Mousectl *m;
	Point p;
	int fd, i;

	for(m = arg;;){
		recvul(m->resizec);
		if(getwindow(display, Refnone) < 0)
			sysfatal("getwindow: %r");
		if((Dx(screen->r) != nelem(w) * WWD
		 || Dy(screen->r) != WHT + font->height)
		&&(fd = open("/dev/wctl", OWRITE)) >= 0){
			fprint(fd, "resize -dx %d -dy %d",
				nelem(w) * WWD + 2 * Borderwidth,
				WHT + font->height + 2 * Borderwidth);
			close(fd);
		}
		for(i = 0, p = screen->r.min; i < nelem(w); i++, p.x += WWD)
			w[i] = rectaddpt(Rect(0, 0, WWD, WHT), p);
		for(i = nelem(b), p.x -= WWD + BWD / 2; i--; p.x -= WWD){
			b[i] = rectaddpt(Rect(0, 0, BWD, BHT), p);
			if(i % 5 == 0 || i % 5 == 2)
				p.x -= WWD;
		}
		infop = Pt(screen->r.min.x, screen->r.max.y - font->height);
		redraw();
	}
}

void
mthread(void *arg)
{
	Mousectl *m;
	int i;

	for(m = arg;;){
		recv(m->c, m);
		switch(m->buttons){
		default:
			continue;
		case 1:
			for(i = 0; i < nelem(b); i++)
				if(ptinrect(m->xy, b[i])){
					on[oct*12+boff[i]] |= 2;
					goto draw;
				}
			for(i = 0; i < nelem(w); i++)
				if(ptinrect(m->xy, w[i])){
					on[oct*12+woff[i]] |= 2;
					break;
				}
			break;
		case 2:
			i = menuhit(2, m, &b2, nil);
			if(i >= 0 && i < WAVES)
				wavn = i;
			break;
		case 4:
			for(i = 0; i < nelem(b); i++)
				if(ptinrect(m->xy, b[i])){
					on[oct*12+boff[i]] &= 1;
					goto draw;
				}
			for(i = 0; i < nelem(w); i++)
				if(ptinrect(m->xy, w[i])){
					on[oct*12+woff[i]] &= 1;
					break;
				}
			break;
		}
draw:		redraw();
	}
}

void
kproc(void *)
{
	int fd, n, i;
	char buf[128], *p;

	if((fd = open("/dev/kbd", OREAD)) < 0)
		sysfatal("open: %r");
	for(;;){
		if((n = read(fd, buf, sizeof(buf) - 1)) < 0)
			sysfatal("read: %r");
		buf[n] = '\0';
		for(p = buf; p - buf < n;){
			if(*p++ != 'c'){
				if(strchr(p, Kdel)){
					close(fd);
					threadexitsall(nil);
				}
				if(strchr(p, 'a') && oct < OCTS - 2)
					oct++;
				if(strchr(p, 'z') && oct)
					oct--;
				if(strchr(p, 's') && vol < 126)
					vol += 7;
				if(strchr(p, 'x') && vol > 6)
					vol -= 7;
				for(i = 0; i < strlen(key); i++){
					if(strchr(p, key[i]))
						on[12 * oct + i] |= 1;
					else
						on[12 * oct + i] &= 2;
				}
				redraw();
			}
			while(*p++)
				;
		}
	}
}

void
threadmain(int,char *argv[])
{
	Mousectl *m;
	int fd, i, s;
	uchar buf[BUF], *p;

	for(i = 0; i < WAV / 2; i++){
		wav[SAW][i] = 64 - 2 * 64 * i / WAV;
		wav[TRI][i] = 64 - 64 * i * 4 / WAV;
		wav[SIN][i] = 64 * sin(2 * PI * i / WAV);
		wav[SQ][i] = -64;
	}
	for(; i < WAV; i++){
		wav[SAW][i] = 64 - 2 * 64 * i / WAV;
		wav[TRI][i] = 64 * (i - WAV / 2) * 4 / WAV - 64;
		wav[SIN][i] = 64 * sin(2 * PI * i / WAV);
		wav[SQ][i] = 64;
	}
	Δ[0] = ((1<<30) / RATE * 1/1) << 5;
	Δ[1] = ((1<<30) / RATE * 17/16) << 5;
	Δ[2] = ((1<<30) / RATE * 9/8) << 5;
	Δ[3] = ((1<<30) / RATE * 19/16) << 5;
	Δ[4] = ((1<<30) / RATE * 5/4) << 5;
	Δ[5] = ((1<<30) / RATE * 21/16) << 5;
	Δ[6] = ((1<<30) / RATE * 11/8) << 5;
	Δ[7] = ((1<<30) / RATE * 3/2) << 5;
	Δ[8] = ((1<<30) / RATE * 13/8) << 5;
	Δ[9] = ((1<<30) / RATE * 27/16) << 5;
	Δ[10] = ((1<<30) / RATE * 7/4) << 5;
	Δ[11] = ((1<<30) / RATE * 15/8) << 5;
	for(i = 0; i < NOTES; i++)
		Δ[i] = Δ[i%12] * powu32int(2,i/12);
	if((fd = open("/dev/audio", OWRITE)) < 0)
		sysfatal("open: %r");
	if(initdraw(nil, nil, argv0 = argv[0]) < 0)
		sysfatal("initdraw: %r");
	if((down = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen)) == nil)
		sysfatal("allocimage: %r");
	if((m = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if(threadcreate(rthread, m, mainstacksize) < 0)
		sysfatal("threadcreate: %r");
	if(threadcreate(mthread, m, mainstacksize) < 0)
		sysfatal("threadcreate: %r");
	if(proccreate(kproc, nil, mainstacksize) < 0)
		sysfatal("proccreate: %r");
	sendul(m->resizec, 1);
	for(;;){
		for(p = buf; p - buf < BUF; p += 4){
			for(i = 0, s = 0; i < NOTES; i++)
				if(on[i])
					s += wav[wavn][(θ[i] += Δ[i]) >> 25];
			s *= vol;
			p[0] = p[2] = s;
			p[1] = p[3] = s >> 8;
		}
		if(write(fd, buf, BUF) != BUF)
			break;
		yield();
	}
	close(fd);
}

A  => xenihak.c +206 -0
@@ 1,206 @@
/* Amavect!
 * Xenihak
 * to play: 6.out >/dev/audio 
 * (turn down your volume)
 */
#include <u.h>
#include <libc.h>
#include <bio.h>

typedef struct Bytebeat Bytebeat;
typedef struct Sound Sound;
typedef struct Audio Audio;

/* unsignedlonglongbeat? */
struct Bytebeat{
	uvlong l;
	uvlong r;
};

/* continuous sounds are to be modelled with precision */
struct Sound{
	double l;
	double r;
};

/* audio(3) */
struct Audio{
	short l;
	short r;
};

/* unnecessary but whatever */
Audio
bbtoaudio(Bytebeat bb)
{
	Audio a;
	a.l = (short)(bb.l&0xFFFF);
	a.r = (short)(bb.r&0xFFFF);
	return a;
}

Sound
audiotosound(Audio a)
{
	Sound s;
	s.l = (double)a.l / (1<<15); /* avoid clipping for a.l=-1<<15 */
	s.r = (double)a.r / (1<<15);
	return s;
}

Audio
soundtoaudio(Sound s)
{
	Audio a;
	a.l = (short)(s.l * ((1<<15) - 1)); /* avoid clipping for s.l=1.0 */
	a.r = (short)(s.r * ((1<<15) - 1));
	return a;
}

Sound
nextpan(uvlong t)
{
	Sound m;
	m.l = cos(t / (2 * 44100.0));
	m.r = sin(t / (2 * 44100.0));
	return m;
}

Sound
swapchan(Sound s)
{
	double d;
	d = s.l;
	s.l = s.r;
	s.r = d;
	return s;
}

Sound
nextvol(uvlong t)
{
	Sound v;
	v.l = sin(t / 200000.0);
	v.r = v.l;
	return v;
}

Sound
nextvol2(uvlong t)
{
	Sound v;
	v.l = cos(t / 200000.0);
	v.r = v.l;
	return v;
}
Sound
soundmod(Sound s, Sound m)
{
	s.l *= m.l;
	s.r *= m.r;
	return s;
}

Sound
soundmix(Sound s, Sound t)
{
	s.l = (s.l + t.l) / 2.0;
	s.r = (s.r + t.r) / 2.0;
	return s;
}

/* insert bytebeat formula here */
Bytebeat
next(uvlong t)
{
	Bytebeat bb;
	bb.l = (7*t<<7)&(666666|t>>4) ^ ((19*t<<6)%(1<<16))|(t>>1) ^ (3*t<<9&t>>2)^ (13*t<<10&t>>3);
	bb.r = bb.l;
	return bb;
}

Bytebeat
next2(uvlong t)
{
	Bytebeat bb;
	bb.l = (17*t<<7)&(666666|t>>7) ^ (11*t<<8&t>>6) ^ (23*t<<9&t>>3);
	bb.r = bb.l;
	return bb;
}

Bytebeat
nextdrop(uvlong t)
{
	Bytebeat bb;
	uvlong u, s, p, hat, snare, kick, bass, mel;

	hat = ( ((t*t*t)/(t%256 + 1))|( (((t<<1)|(t<<2) + (1<<15))|(t<<2)|(t<<((t<<2)&(t<<3)))|(t<<4)*(t>>13&t>>12)) ) );
	u = t+(1<<14);
	s = t+(3<<13);
	p = (t*1/1)*(((t>>17)+3)%4/3) + (t*3/4)*(((t>>17)+2)%4/3) + (t*7/8)*(((t>>17)+1)%4/3) + (t*15/16)*(((t>>17)+0)%4/3);
	kick = ( (128*t * ((1<<5)-((t>>8)%(1<<5)))/(1<<4))|( (((t>>1)&((t>>1)+(1<<15)))|t|(t<<1)|(t<<2)|(t<<3)) & (((s>>1)&((s>>1)+(1<<15)))|s|(s<<1)|(s<<2)|(s<<3)) ) );
	bass = (((1000*t/1001<<6) & (1001*t/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
	snare = ( ((t<<8)%666666) ^ ((t<<5)%(1<<16) + 1) ) | ( (u&(u+(1<<15))|(u<<1)|(u<<2)|(u<<3)) );
	mel = (7*t<<7&t>>2)|(9*t<<7&t>>3)|(19*t<<6&t>>4)|(11*t<<7&t>>5);

	if(t >= 1<<20 && t < (1<<21) - (1<<17)){
		bb.l = hat;
	}else if(t >= 1<<21 && t < 1<<22){
		bb.l = (kick + snare + hat) ^ bass;
	}else if(t >= 1<<22 && t < (1<<22) + (1<<20)){
		bb.l = (snare + hat) | mel;
	}else if(t >= (1<<22) + (1<<20) && t < (3<<21) - (1<<17)){
		bb.l = hat | mel;
	}else if(t >= 3<<21 && t < (1<<23) - (1<<17)){
		bass = (((1000*p/1001<<6) & (1001*p/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
		bb.l = (kick + snare + hat) ^ bass;
	}else if(t >= (1<<23) - (1<<17) && t < 1<<23){
		bass = (((1000*p/1001<<6) & (1001*p/1000<<6)) - 1) & (t<<((999*t/998>>1|t>>8)*(t>>13&t>>12)));
		bb.l = (snare + hat) ^ bass;
	}else{
		bb.l = 0;
	}
	bb.r = bb.l;
	return bb;
}

void
main(void)
{
	uvlong t;
	Bytebeat b1, b2, b3;
	Audio a;
	Sound s1, s2, s3, m1, m2, v1, v2;
	Biobuf bfile;
	
	if(Binit(&bfile, 1, OWRITE) == Beof)
		sysfatal("Binit failed!");
	
	for(t = 0; t < (1<<23) + (1<<20); t++){
		b1 = next(t);
		b2 = next2(t);
		s1 = audiotosound(bbtoaudio(b1));
		s2 = audiotosound(bbtoaudio(b2));
		m1 = nextpan(t);
		m2 = swapchan(m1);
		v1 = nextvol(t);
		v2 = nextvol2(t);
		s1 = soundmod(s1, m1);
		s2 = soundmod(s2, m2);
		s1 = soundmod(s1, v1);
		s2 = soundmod(s2, v2);
		s1 = soundmix(s1, s2);
		b3 = nextdrop(t);
		s3 = audiotosound(bbtoaudio(b3));
		s3 = soundmix(s3, s1);
		s3.l *= 4.0/3.0; /* normalize, as max(s3)≈0.749999 due to panning phase */
		s3.r *= 4.0/3.0;
		a = soundtoaudio(s3);
		if(Bwrite(&bfile, &a.l, sizeof(a.l)) < 0)
			sysfatal("Bwrite failed!");
		if(Bwrite(&bfile, &a.r, sizeof(a.r)) < 0)
			sysfatal("Bwrite failed!");
	}
	
	exits(nil);
}