Home 
 
# GIF Jam
# Take an image (in pnm format), scan the pixels in a variety of
# ways, and use the RGB values to produce music.

function gifjam(fname,xval,yval,scantype,redrange,greenrange,bluerange) {

	inc = 1b/4
	Note1 = 'a'
	Note1.dur = inc
	Note1.length = inc
	Rest1 = 'r'
	Rest1.length = inc

	Maxval = 0
	if ( readpnm(fname) != 0 ) {
		print("Unrecognized file format");
		return()
	}
	Nrows = sizeof(CellR);
	Ncols = sizeof(CellR[0]);
	# print("ranges=",redrange,greenrange,bluerange);

	RedRange = getrange(redrange);
	GreenRange = getrange(greenrange);
	BlueRange = getrange(bluerange);

	# print("Nrows=",Nrows," Ncols=",Ncols);
	# print("xval=",xval," yval=",yval);
	y = integer(yval) * Nrows / 150
	x = integer(xval) * Ncols / 300

	NotesR = ''
	NotesG = ''
	NotesB = ''

	if ( scantype ~~ "Scan 3.*" ) {
		scanline(y) ; scanline(y+3) ; scanline(y+6)
	}
	else if ( scantype ~~ "Scan 1.*" ) {
		scanline(y)
	}
	else if ( scantype ~~ "Scan 6.*" ) {
		scanline(y) ; scanline(y+2) ; scanline(y+4)
		scanline(y+6) ; scanline(y+8) ; scanline(y+10)
	}
	else if ( scantype ~~ "Spiral.*" ) {
		spiralout(128,x,y)
	}
	else if ( scantype ~~ "Four.*" ) {
		spiralout(128,x,y)
	}
	else {
		print("Unrecognized scan type: ",scantype)
	}

	if ( typeof(RedRange) == "array" ) {
		NotesR.chan = 1;
		NotesR = scadjust(NotesR,transpose(scale_dorian(),'a'));
	}
	NotesR = NotesR{ rand(2)==0 };

	if ( typeof(GreenRange) == "array" ) {
		NotesG.chan = 2;
		NotesG = scadjust(NotesG,transpose(scale_dorian(),'a'));
	}
	NotesG = NotesG{ rand(2)==0 }

	if ( typeof(BlueRange) == "array" ) {
		NotesB.chan = 3;
		NotesB = scadjust(NotesB,transpose(scale_dorian(),'a'));
	}
	NotesB = NotesB{ rand(2)==0 }

	p = (NotesR | NotesG | NotesB)
	p = p | makerootevery(p{??.chan!=10},2b)

	writemf(p,"www.mid")
	writelines(p,"www.lines")
}

function getrange(range) {
	r = []
	if ( range ~~ "High .*" ) {
		r["high"] = 110
		r["low"] = 70
	}
	else if ( range ~~ "Medium-High .*" ) {
		r["high"] = 100
		r["low"] = 60
	}
	else if ( range ~~ "Medium .*" ) {
		r["high"] = 90
		r["low"] = 50
	}
	else if ( range ~~ "Medium-Low .*" ) {
		r["high"] = 80
		r["low"] = 40
	}
	else if ( range ~~ "Low .*" ) {
		r["high"] = 70
		r["low"] = 30
	}
	else if ( range ~~ "None.*" ) {
		return(-1)
	}
	else if ( range ~~ "Drums.*" ) {
		return(-2)
	}
	else if ( range ~~ "Chords.*" ) {
		return(-3)
	}
	r["span"] = r["high"] - r["low"]
	return(r)
}

function spiralout(nnts,x,y) {

	p = ''
	oy = y;
	dx = 1
	dxdir = -1
	dy = 0
	dydir = 1
	ndx = 0
	ndy = 0
	ndxsofar = 0
	ndysofar = 0
	for ( n=0; n<nnts; n++) {

		if ( x<0 || y<0 || x>=Ncols || y>=Nrows )
			break;

		usecell(y,x)

		x += dx
		y += dy

		if ( ++ndxsofar > ndx ) {
			ndxsofar = 0;
			if ( dx == 0 ) {
				dx = 1 * dxdir
				dy = 0
				dxdir = -dxdir
				ndx++
			}
			else {
				dx = 0
				dy = 1 * -dxdir
			}
		}
	}
	return(p)
}

function scanline(y) {
	for ( x=0; x<Ncols; x++ ) {
		usecell(y,x)
	}
}

Drums = [0=35,1=36,2=37,3=38,4=39,5=41,6=42,7=46,8=47,
	9=48,10=50,11=53,12=54,13=56,14=60,15=61,16=62,17=63]
Chords = [0='c e g',1='f a c',2='d f+ a',3='g b d',4='a c+ e']

function usecell(y,x) {

	v = (CellR[y][x])
	if ( v != 0 && v != Maxval ) {
		if ( typeof(RedRange) == "array" ) {
			v2 = v * RedRange["span"] / (Maxval)
			Note1.pitch = v2 + RedRange["low"]
			NotesR += Note1
		}
		else if ( RedRange == -2 ) {
			Note1.pitch = Drums[v%sizeof(Drums)]
			Note1.chan = 10
			NotesR += Note1
		}
		else if ( RedRange == -3 ) {
			ch = Chords[v%sizeof(Chords)]
			ch.dur = Note1.dur
			ch.length = Note1.length
			NotesR += ch
		}
	}
	else {
		NotesR += Rest1
	}

	v = (CellG[y][x])
	if ( v != 0 && v != Maxval ) {
		if ( typeof(GreenRange) == "array" ) {
			v2 = v * GreenRange["span"] / (Maxval)
			Note1.pitch = v2 + GreenRange["low"]
			NotesG += Note1
		}
		else if ( GreenRange == -2 ) {
			Note1.pitch = Drums[v%sizeof(Drums)]
			Note1.chan = 10
			NotesG += Note1
		}
	}
	else {
		NotesG += Rest1
	}

	v = (CellB[y][x])
	if ( v != 0 && v != Maxval ) {
		if ( typeof(BlueRange) == "array" ) {
			v2 = v * BlueRange["span"] / (Maxval)
			Note1.pitch = v2 + BlueRange["low"]
			NotesB += Note1
		}
		else if ( BlueRange == -2 ) {
			Note1.pitch = Drums[v%sizeof(Drums)]
			Note1.chan = 10
			NotesB += Note1
		}
	}
	else {
		NotesG += Rest1
	}
}

function readpnm(fname) {
	f = open(fname)
	Words = []
	Used = 0
	Type = getword(f)

	cols = getword(f)
	rows = getword(f)
	Maxval = getword(f)
	CellR = []
	CellG = []
	CellB = []
	if ( Type == "P2" ) {
		# greyscale
		for ( r=0; r<rows; r++ ) {
			CellR[r] = []
			CellG[r] = []
			CellB[r] = []
			for ( c=0; c<cols; c++ ) {
				i = integer(getword(f))
				if ( i == Eof ) {
					print("Premature EOF!?");
					break;
				}
				CellR[r][c] = i
				CellG[r][c] = i
				CellB[r][c] = i
			}
		}
		return(0)
	}
	else if ( Type == "P3" ) {
		# color
		for ( r=0; r<rows; r++ ) {
			CellR[r] = []
			CellG[r] = []
			CellB[r] = []
			for ( c=0; c<cols; c++ ) {
				ir = integer(getword(f))
				if ( ir == Eof ) {
					print("Premature EOF!?");
					break;
				}
				ig = integer(getword(f))
				if ( ig == Eof ) {
					print("Premature EOF!?");
					break;
				}
				ib = integer(getword(f))
				if ( ib == Eof ) {
					print("Premature EOF!?");
					break;
				}
				CellR[r][c] = ir
				CellG[r][c] = ig
				CellB[r][c] = ib
			}
		}
		return(0)
	}
	else {
		print("Unrecognized image type: ",Type);
		return(1)
	}
}

function getword(f) {
	if ( Used < sizeof(Words) ) {
		return(Words[Used++])
	}
	while (1) {
		ln = get(f)
		if ( ln == Eof )
			return(Eof)
		Words = split(ln)
		if ( sizeof(Words) > 0 )
			break;
	}
	Used = 0
	return (Words[Used++])
}