//PixiTracker v0.3
//Code by Alex Zolotov (nightradio@gmail.com)
//www.warmplace.ru

FREQ = 8000
CHANNELS = 1
SOUND_BUF_SIZE = 2000

xsize = 240
ysize = 240
hx = xsize / 2
hy = ysize / 2

resize_pixi( 0, xsize, ysize )

low_vol_color = #606060
clear_color = #203040

MAKE_FONT
make_pixi( font )
pixi_font( font )

MAKE_SAMPLES
make_pixi( zul )

//LOGO #############################
clear( BLACK )
y = -hy while( y < hy ) {
x = -hx while( x < hx ) {
r = (csin(x*3)*ccos(y*2))/128+128
g = (csin(x*2)+csin(y*2))+128
b = (csin(x*1)*ccos(y*1))/128+128
if y < -hy+64 { 
	s = ( -hy+64 - y ) * 8
	r - s
	g - s
	b - s
}
fbox( x, y, 4, 4, get_color( r/2, g/2, b/2 ) )
x + 4
}
y + 4
}
d = 0
logo_str = "PIXITRACKER V0.3
MUSIC EDITOR
BY ALEX ZOLOTOV"
print( logo_str, -hx+2, -hy+8, WHITE )
start_timer( 0 )
logo1:
handle_pen_keys( { d = 1 }, {}, { if d { logo_end = 1 } } )
if get_timer( 0 ) > 4 * 1000 { logo_end = 1 }
frame(0)
if logo_end = 0 { go logo1 }
//##################################

//Song info:
max_pats = 10
pat_xs = 16
pat_ys = 8
pats = new_array( max_pats )
pats_loop = new_string( max_pats )
cur_loop = 1
p = 0 while( p < max_pats )
{
	pats[ p ] = new_array( pat_xs * pat_ys )
	pats_loop[ p ] = 1
	p + 1
}
copy_pat = new_array( pat_xs * pat_ys )
last_pat = 0
cur_pat = 0
cur_line = 0
cur_note = 16
max_samples = 16
samples = new_array( max_samples )
fine = new_string( 128 )
rand_seed( 0 )
smp_size = 1024
s = 0 while( s < max_samples )
{
	samples[ s ] = new_string( smp_size )
	fine[ s ] = 0
	s + 1
}
// SAMPLE GENERATION /\/\/\/\/\/\/\/\
smp = samples[ 0 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * 16 ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 1 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * p * p ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 2 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * p ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 3 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * (256-p/4) ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 4 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * 16 + (rand&63) ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 5 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( (rand&63) * v ) / 1024
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 6 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = rand&63
	p + 1 v - 1
}
smp = samples[ 7 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * ccos( p / 16 )/16 ) / 2 ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 8 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p + csin( p )*128 ) / 4 ) * v ) / 1024
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 9 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( (rand&63) * csin( p/2 ) ) / 128
	p + 1 v - 1
}
smp = samples[ 10 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ((p&63)-32) + ((p&15)-8)
	p + 1 v - 1
}
smp = samples[ 11 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( ((p&63)-32) + ((p&15)-8) ) * v ) / 1024
	p + 1 v - 1
}
smp = samples[ 12 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( (((p*p)&63)-32) + ((p&15)-8) ) * v ) / 1024
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 13 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( (((rand&63)-32)*(p&63))/32 ) * v ) / 1024
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 13 ]
v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( rand&63 ) * (1024-v) ) / 1024
	p + 1 v - 1
}
rand_seed( 10 )
smp = samples[ 14 ]
d = 16 v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * d ) / 4 ) * v ) / 1024
	if (p&255) = 0 { d = rand&127 }
	p + 1 v - 1
}
rand_seed( 0 )
smp = samples[ 15 ]
d = 16 v = 1024 p = 0 while( p < smp_size ) {
	smp[ p ] = ( ( csin( p * d ) / 4 ) * v ) / 1024
	if (p&63) = 0 { d = rand&127 }
	p + 1 v - 1
}
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
cur_sample = 0
cur_vol = 15
bpm = 125
gvol = 128
play = 0
pvol = new_array( pat_ys + 1 )
psmp = new_array( pat_ys + 1 )
pnote = new_array( pat_ys + 1 )
pptr = new_array( pat_ys + 1 )

SOUND_INIT

redraw_gui = 1
REDRAW
start:

handle_pen_keys( 
{
	//DOWN:
	check_pen = 1
	REDRAW
},
{
	//MOVE:
},
{
	//UP:
}
)

filename = "......................................................................................................................................."
if wav_export 
{
	transp( 200 )
	clear( BLACK )
	transp( 256 )
	print( "SELECT SAMPLING FREQUENCY", -(25*5)/2, -8, WHITE )
	x = -(9*5*5)/2
	print( "[ 48000 ][ 44100 ][ 22050 ][ 11025 ][ 8000  ]", x, 0, WHITE )
	r = 0
wex:
	handle_pen_keys( {}, {}, { if gpy < 90 { r = 1 + (gpx-x)/(9*5) } } )
	frame( 0 )
if r = 0 { go wex }
	if r = 1 { EXPORT_FREQ = 48000 }
	if r = 2 { EXPORT_FREQ = 44100 }
	if r = 3 { EXPORT_FREQ = 22050 }
	if r = 4 { EXPORT_FREQ = 11025 }
	if r = 5 { EXPORT_FREQ = 8000 }
	if file_dialog( filename, "Save to WAV", "wav", "pixitracker_swav" ) { SAVE_WAV }
}
wav_export = 0

if need_load 
{
	if file_dialog( filename, "Load song", "piximod", "pixitracker_lmod" ) { LOAD_SONG }
	cur_pat = 0
	cur_line = 0
	cur_loop = pats_loop[ 0 ]
}
need_load = 0

if need_save 
{
	if file_dialog( filename, "Save song", "piximod", "pixitracker_smod" ) { SAVE_SONG }
}
need_save = 0

if need_lsample 
{
	if file_dialog( filename, "Load WAV sample", "wav/wave", "pixitracker_lwav" ) { LOAD_WAV_SAMPLE }
}
need_lsample = 0

REDRAW

SOUND_HANDLER

frame( 0 )

go start


REDRAW:
if ( redraw_gui = 0 ) & ( check_pen = 0 ) { ret }
if redraw_gui { 
	clear( clear_color ) 
	print( "PIXITRACKER V0.3", hx - 16*5, -hx + 1, #A0A0A0 )
}
xs = 10
ys = 10
cx = -( pat_xs * xs ) / 2
cy = -( pat_ys * ys ) / 2
cx_size = pat_xs * xs
cy_size = pat_ys * ys
pat = pats[ cur_pat ]
pp = 0
cysize = cy + cy_size
yy = cy while( yy < cysize ) {
	xx = cx while( xx < cx + cx_size ) 
	{
		if redraw_gui { 
			v = (pat[pp]&15)*16
			fbox( xx, yy, xs-1, ys-1, get_blend( low_vol_color, YELLOW, v ) ) 
			if v { fpixi( zul, xx + xs/2-1, yy + ys/2-1, 1, 0, (pat[pp]/16)&15 ) }
		}	
		if check_pen 
		{
			if gpr( xx, yy, xs, ys ) {
				if pat[pp] { pat[pp] = 0 } else { pat[pp] = cur_vol | (cur_sample*16) | (cur_note*16*16) }
				redraw_gui = 2
				check_pen = 0
			}
		}
		xx + xs
		pp + 1
	}
	yy + ys
}
//GLOBAL VOLUME:
if redraw_gui { 
	vy = cy + cy_size - (gvol*cy_size)/256
	line( -hx, vy, cx - 2, vy, WHITE )
	print( "$gvol", -hx, vy + 2, WHITE )
}
if check_pen {
	if gpr( -hx, cy, cx+hx, cy_size ) { 
		gvol = 256 - ( ( ( gpy - cy ) * 256 ) / cy_size )
		if gvol < 0 { gvol = 0 }
		if gvol > 255 { gvol = 255 }
		sound_volume( gvol )
		redraw_gui = 2 check_pen = 0
	}
}
//EDIT:
x = cx + cx_size + 0
y = cy
xs = hx - cx
ys = 15
if redraw_gui { 
	fbox( x, y, xs, ys, #909090 )
	print( "COPY", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) {
		pat = pats[ cur_pat ]
		p = 0 while( p < pat_xs * pat_ys ) { copy_pat[ p ] = pat[ p ] p + 1 }
	}
}
y + 16
if redraw_gui { 
	fbox( x, y, xs, ys, #909090 )
	print( "PASTE", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) {
		pat = pats[ cur_pat ]
		p = 0 while( p < pat_xs * pat_ys ) { pat[ p ] = copy_pat[ p ] p + 1 }
		redraw_gui = 2 check_pen = 0
	}
}
y + 16
if redraw_gui { 
	fbox( x, y, xs, ys, #909090 )
	print( "CLEAR", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) {
		pat = pats[ cur_pat ]
		p = 0 while( p < pat_xs * pat_ys ) { pat[ p ] = 0 p + 1 }
		redraw_gui = 2 check_pen = 0
	}
}
//PATS:
xs = 16
ys = 16
y = cy + cy_size + 8
if redraw_gui { print( "LOOPS", -(max_pats*xs)/2 - 32, cy + cy_size + 35, #808080 ) }
p = 0 while( p < max_pats ) {
	x = -(max_pats*xs)/2 + p*xs
	if x > hx { p = 1111111 }
	if redraw_gui 
	{ 
		if p = cur_pat { fbox( x, y, xs - 2, ys, GREEN ) }
		box( x, y, xs - 2, ys, WHITE )
		print( "$p", x + 2, y + 2, WHITE )
		if last_pat = p { 
			fbox( x, y + ys + 2, xs - 1, ys / 2, RED ) 
			print( "END", x, y + ys + 3, BLACK )
		}
		loop = pats_loop[ p ]
		print( "$loop", x, y + ys + 11, #808080 )
	}
	if check_pen 
	{
		if gpr( x, y, xs, ys ) { cur_pat = p cur_loop = pats_loop[ cur_pat ] cur_line = 0 redraw_gui = 2 check_pen = 0 }
		if gpr( x, y + ys + 2, xs - 1, ys / 2 ) { last_pat = p redraw_gui = 2 check_pen = 0 }
		if gpr( x, y + ys + 11, xs - 1, ys / 2 ) { 
			pats_loop[ p ] = pats_loop[ p ] + 1 
			if pats_loop[ p ] > 4 { pats_loop[ p ] = 1 }
			redraw_gui = 2 check_pen = 0 
		}
	}
	p + 1
}
//Notes:
xs = 7
ys = 16
if redraw_gui { 
	print( "NOTE:", -hx + 1, -hy + 1, #909090 ) 
	fbox( hx - 16, -hy + 7, 16, ys - 1, #909090 )
	print( "++", hx - 16 + 1, -hy + 7 + 1, WHITE )
}
n = 0 while( n < (xsize - 16) / xs ) {
	x = -hx + n * xs
	y = -hy + 7
	if redraw_gui 
	{
		ncol = #909090
		if n+noteoff = cur_note { fbox( x, y, xs-1, ys-1, YELLOW ) } else { fbox( x, y, xs-1, ys-1, ncol ) }
		if (n+noteoff)%12 = 0 { fbox( x+1, y+1, 1, 1, WHITE ) }
	}
	if check_pen 
	{
		if gpr( hx - 16, -hy + 7, 16, ys )
		{
			if noteoff = 0 { noteoff = 30 } else { noteoff = 0 }
			redraw_gui = 2 check_pen = 0 
		}
		if gpr( x, y, xs, ys ) 
		{ 
			cur_note = n+noteoff
			redraw_gui = 2 check_pen = 0 
			pvol[ pat_ys ] = cur_vol
			psmp[ pat_ys ] = cur_sample
			pnote[ pat_ys ] = cur_note
			pptr[ pat_ys ] = 0
		}
	}
	n + 1
	if n+noteoff >= 60 { n = 999999 }
}
//Samples:
xs = 10
ys = 10
y = -hy + 8+16+7
x = -( max_samples * xs ) / 2 + 16*xs
ccc = ( -( max_samples * xs ) / 2 + hx )
cc = -hx + ccc / 2
if redraw_gui { 
	print( "SAMPLES:", -hx + 1, -hy + 8+16+1, #909090 ) 
	fbox( x, y, hx-x, ys-1, #909090 )
	print( "LOAD", x+1, y+1, WHITE )
	finetune = fine[ cur_sample ]
	if finetune > 7 { finetune - 16 }
	if finetune = 0 { fbox( cc + finetune*2, y, 2, ys-1, WHITE ) } else { fbox( cc + finetune*2, y, 2, ys-1, #909090 ) }
}
if check_pen {
	if gpr( x, y, hx-x, ys ) { need_lsample = 1 redraw_gui = 2 check_pen = 0 }
	if gpr( -hx, y, ccc, ys ) { 
		finetune = ( gpx - cc ) / 2 
		if finetune > 7 { finetune = 7 }
		if finetune < -8 { finetune = -8 }
		if finetune < 0 { finetune + 16 }
		fine[ cur_sample ] = finetune
		redraw_gui = 2 check_pen = 0
	}
}
n = 0 while( n < max_samples ) {
	x = -( max_samples * xs ) / 2 + n*xs
	if redraw_gui 
	{
		if n = cur_sample { fbox( x, y, xs-1, ys-1, YELLOW ) } else { fbox( x, y, xs-1, ys-1, #A0A0A0 ) }
		fpixi( zul, x + xs/2-1, y + ys/2-1, 1, 0, n )
	}
	if check_pen 
	{
		if gpr( x, y, xs, ys ) { cur_sample = n redraw_gui = 2 check_pen = 0 }
	}
	n + 1
}
//Volumes:
xs = 10
ys = 10
if redraw_gui { print( "VOLUME:", -hx + 1, -hy + 8+16+17+2, #909090 ) }
n = 0 while( n < 16 ) {
	x = -( 16 * xs ) / 2 + n*xs
	y = -hy + 8+16+17+8
	if redraw_gui 
	{
		if n = cur_vol { fbox( x, y, xs-1, ys-1, YELLOW ) } else { fbox( x, y, xs-1, ys-1, get_blend( low_vol_color, WHITE, n*16 ) ) }
	}
	if check_pen 
	{
		if gpr( x, y, xs, ys ) { cur_vol = n redraw_gui = 2 check_pen = 0 }
	}
	n + 1
}
if redraw_gui { print( "$cur_vol", -( 16 * xs ) / 2 + 16*xs, y+2, #808080 ) }
//Play:
c = #808080
if play { c = #FF7040 }
xs = 64
ys = 32
x = -hx
y = hy - ys
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "PLAY", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { play = play ^ 1 if play { PLAY } else { STOP } redraw_gui = 2 check_pen = 0 }
}
//BPM:
c = #808080
xs = 32
ys = 20
x = -hx + 64 + 1
y = hy - 32
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "-BPM", x + 1, y + 1, WHITE )
	print( "$bpm", x + 32-7, y + 20 + 3, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { bpm - 1 redraw_gui = 2 check_pen = 0 }
}
xs = 32
ys = 20
x = -hx + 64 + xs + 2
y = hy - 32
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "+BPM", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { bpm + 1 redraw_gui = 2 check_pen = 0 }
}
//WAV EXPORT:
c = #908070
xs = 32
ys = 32
x = hx - xs
y = hy - ys
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "WAV
EXPORT", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { redraw_gui = 2 check_pen = 0 wav_export = 1 }
}
//LOAD:
c = #808080
//xs - 5
x - (xs+1)
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "LOAD", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { need_load = 1 redraw_gui = 2 check_pen = 0 }
}
//SAVE:
c = #808080
x - (xs+1)
if redraw_gui 
{
	fbox( x, y, xs, ys, c )
	print( "SAVE", x + 1, y + 1, WHITE )
}
if check_pen 
{
	if gpr( x, y, xs, ys ) { need_save = 1 redraw_gui = 2 check_pen = 0 }
}

redraw_gui - 1
check_pen - 1
if redraw_gui < 0 { redraw_gui = 0 }
if check_pen < 0 { check_pen = 0 }
ret

MAKE_FONT:
o = WHITE
font="
 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
.....
.....
.....
.....
.....
.....
+
 + + + + + + + + + +
....
..o.
.ooo
..o.
....
+ 
+ 
....
....
oooo
....
....
+ 
+ 
+
oooo
o..o
o..o
o..o
oooo
+
...o
...o
...o
...o
...o
+
oooo
...o
oooo
o...
oooo
+
oooo
...o
oooo
...o
oooo
+
o..o
o..o
oooo
...o
...o
+
oooo
o...
oooo
...o
oooo
+
oooo
o...
oooo
o..o
oooo
+
oooo
...o
...o
...o
...o
+
oooo
o..o
oooo
o..o
oooo
+
oooo
o..o
oooo
...o
oooo
+
 + + + + + + +
oooo
o..o
oooo
o..o
o..o
+
oooo
o..o
ooo.
o..o
oooo
+
oooo
o...
o...
o...
oooo
+
ooo.
o..o
o..o
o..o
ooo.
+
oooo
o...
oooo
o...
oooo
+
oooo
o...
oooo
o...
o...
+
oooo
o...
o...
o..o
oooo
+
o..o
o..o
oooo
o..o
o..o
+
..o.
..o.
..o.
..o.
..o.
+
...o
...o
...o
o..o
.oo.
+
o..o
o.o.
oo..
o.o.
o..o
+
o...
o...
o...
o...
oooo
+
o..o
oooo
o..o
o..o
o..o
+
o..o
oo.o
o.oo
o..o
o..o
+
oooo
o..o
o..o
o..o
oooo
+
oooo
o..o
oooo
o...
o...
+
oooo
o..o
o..o
o.oo
oooo
+
oooo
o..o
oooo
o.o.
o..o
+
oooo
o...
oooo
...o
oooo
+
oooo
..o.
..o.
..o.
..o.
+
o..o
o..o
o..o
o..o
oooo
+
o..o
o..o
.oo.
.oo.
.oo.
+
o..o
oooo
oooo
oooo
.oo.
+
o..o
.oo.
.oo.
o..o
o..o
+
o..o
.oo.
..o.
..o.
..o.
+
oooo
..o.
.o..
o...
oooo
"
ret

MAKE_SAMPLES:
i = BLACK
zul="
.i.i.i.
.i...i.
..iii..
i..i..i
.iiiii.
..i.i..
..i.i..
+
.i...i.
.iiiii.
ii.i.ii
.iiiii.
..iii..
..i.i..
...i...
+
.i...i.
iiiiiii
i.ii.ii
iiiiiii
.iiiii.
.i..ii.
.iiiii.
+
.i.i.i.
ii...ii
iiiiiii
i.iii.i
.iiiii.
.i.i.i.
.iiiii.
+
.i.i.i.
ii.i.ii
iiiiiii
i.iii.i
..iii..
.i.i.i.
i.iii.i
+
.i.i.i.
iiiiiii
.iiiii.
i.iii.i
iiiiiii
ii.i.ii
i.iii.i
+
i.iii.i
.iiiii.
i.i.i.i
.iiiii.
...i...
..iii..
.i...i.
+
i..i..i
.iiiii.
...i...
.iiiii.
i.iii.i
.iiiii.
.ii.ii.
+
..iii..
..i.i..
..iii..
.iiiii.
...i...
.iiiii.
ii...ii
+
...i...
.iiiii.
ii.i.ii
iiiiiii
.iiiii.
..i.i..
.ii.ii.
+
..i.i..
...i...
.ii.ii.
ii.i.ii
.iiiii.
..i.i..
.ii.ii.
+
.iiiii.
i..i..i
.iiiii.
..i.i..
...i...
iiiiiii
.ii.ii.
+
.iiiii.
...i...
..iii..
.ii.ii.
..iii..
...i...
.ii.ii.
+
..iii..
i..i..i
.iiiii.
.ii.ii.
.iiiii.
.i...i.
ii..ii.
+
.ii.ii.
..i.i..
.iiiii.
.i.i.i.
iiiiiii
iiiiiii
.iiiii.
+
..iii..
..iii..
iiiiiii
.i.i.i.
.iiiii.
.i...i.
..iii..
+
...i...
.iiiii.
i.i.i.i
.iiiii.
.......
.......
.......
+
i...iii
.iii...
.i.i...
.ii.i..
i..i.ii
i...ii.
i...i..
+
...i...
...ii..
i..iii.
.iiiiii
.iiiiii
.i.i...
.i.i...
+
i...i..
.iii...
iiiii..
.iii...
..i....
.iii...
iiiiiii
+
.iii...
.i.ii..
.iii...
..i...i
..iiii.
.iiiii.
ii..iii
+
.iiiii.
iiiiiii
i..i..i
iiiiiii
ii.i.ii
i.i.i.i
iiiiiii
+
.ii.ii.
.i...i.
ii.i.ii
.i...i.
.ii.ii.
..i.i..
iiiiiii
+
ii.i.ii
.iiiii.
ii.i.ii
.iiiii.
ii.i.ii
.iiiii.
ii.i.ii
+
iii.iii
i..i..i
iii.iii
.i.i.i.
.i...i.
..iii..
...i...
+
ii...ii
iiiiiii
i..i..i
iiiiiii
i..i..i
..iii..
iiiiiii
+
.i...i.
.iiiii.
...i...
iiiiiii
i..i..i
i.iii.i
i.i.i.i
+
iiiiiii
i.iii.i
iii.iii
.i...i.
.iiiii.
..i.i..
.ii.ii.
+
.iiii..
..i.ii.
.iiii..
...i...
iiiiiii
..i.i..
.ii.ii.
+
..iii..
..i.i..
i.iii.i
ii...ii
..i.i..
iii.iii
i.....i
+
...i...
..i.i..
i..i..i
iiiiiii
..i.i..
iiiiiii
i.....i
"
ret

//##########################################################################
//##########################################################################
//##########################################################################
//##########################################################################
//##########################################################################

SOUND_INIT:

sound_volume( 128 )

per_text = "
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113,
107,101,95,90,85,80,75,71,67,63,60,56,

1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
850,802,757,715,674,637,601,567,535,505,477,450,
425,401,379,357,337,318,300,284,268,253,239,225,
213,201,189,179,169,159,150,142,134,126,119,113,
106,100,94,89,84,79,75,71,67,63,59,56,

1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
844,796,752,709,670,632,597,563,532,502,474,447,
422,398,376,355,335,316,298,282,266,251,237,224,
211,199,188,177,167,158,149,141,133,125,118,112,
105,99,94,88,83,79,74,70,66,62,59,56,

1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
838,791,746,704,665,628,592,559,528,498,470,444,
419,395,373,352,332,314,296,280,264,249,235,222,
209,198,187,176,166,157,148,140,132,125,118,111,
104,99,93,88,83,78,74,70,66,62,59,55,

1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
832,785,741,699,660,623,588,555,524,495,467,441,
416,392,370,350,330,312,294,278,262,247,233,220,
208,196,185,175,165,156,147,139,131,124,117,110,
104,98,92,87,82,78,73,69,65,62,58,55,

1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
826,779,736,694,655,619,584,551,520,491,463,437,
413,390,368,347,328,309,292,276,260,245,232,219,
206,195,184,174,164,155,146,138,130,123,116,109,
103,97,92,87,82,77,73,69,65,61,58,54,

1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
820,774,730,689,651,614,580,547,516,487,460,434,
410,387,365,345,325,307,290,274,258,244,230,217,
205,193,183,172,163,154,145,137,129,122,115,109,
102,96,91,86,81,77,72,68,64,61,57,54,

1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
814,768,725,684,646,610,575,543,513,484,457,431,
407,384,363,342,323,305,288,272,256,242,228,216,
204,192,181,171,161,152,144,136,128,121,114,108,
102,96,90,85,80,76,72,68,64,60,57,54,

1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1008,960,
907,856,808,762,720,678,640,604,570,538,504,480,
453,428,404,381,360,339,320,302,285,269,254,240,
226,214,202,190,180,170,160,151,143,135,127,120,
113,107,101,95,90,85,80,75,71,67,63,60,

1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
900,850,802,757,715,675,636,601,567,535,505,477,
450,425,401,379,357,337,318,300,284,268,253,238,
225,212,200,189,179,169,159,150,142,134,126,119,
112,106,100,94,89,84,79,75,71,67,63,59,

1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
894,844,796,752,709,670,632,597,563,532,502,474,
447,422,398,376,355,335,316,298,282,266,251,237,
223,211,199,188,177,167,158,149,141,133,125,118,
111,105,99,94,88,83,79,74,70,66,62,59,

1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
887,838,791,746,704,665,628,592,559,528,498,470,
444,419,395,373,352,332,314,296,280,264,249,235,
222,209,198,187,176,166,157,148,140,132,125,118,
111,104,99,93,88,83,78,74,70,66,62,59,

1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
881,832,785,741,699,660,623,588,555,524,494,467,
441,416,392,370,350,330,312,294,278,262,247,233,
220,208,196,185,175,165,156,147,139,131,123,117,
110,104,98,92,87,82,78,73,69,65,61,58,

1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
875,826,779,736,694,655,619,584,551,520,491,463,
437,413,390,368,347,338,309,292,276,260,245,232,
219,206,195,184,174,164,155,146,138,130,123,116,
109,103,97,92,87,82,77,73,69,65,61,58,

1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
868,820,774,730,689,651,614,580,547,516,487,460,
434,410,387,365,345,325,307,290,274,258,244,230,
217,205,193,183,172,163,154,145,137,129,122,115,
108,102,96,91,86,81,77,72,68,64,61,57,

1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,
862,814,768,725,684,646,610,575,543,513,484,457,
431,407,384,363,342,323,305,288,272,256,242,228,
216,203,192,181,171,161,152,144,136,128,121,114,
108,101,96,90,85,80,76,72,68,64,60,57
"

//~~~~~~~~ Fast creation of numeric array: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ARRAY_SRC = 0		//Text string like "123 456 344 223 122"
ARRAY_RESULT = 0	//Resulted numeric array

go skip_arrays

CREATE_ARRAY:
str_size = get_string_size( ARRAY_SRC )
nums = 0
n = 0
p = 0
CAR_LOOP1:
c = ARRAY_SRC[ p ]
n2 = n
if ( c >= '0' ) & ( c <= '9' ) { n = 1 } else { n = 0 }
if n = 1 & n2 = 0 { nums + 1 }
p + 1
if p < str_size { go CAR_LOOP1 }

//Create empty array:
ARRAY_RESULT = new_array( nums )
n = 0
CAR_LOOP3:
ARRAY_RESULT[ n ] = 0
n + 1
if n < nums { go CAR_LOOP3 }

//Create numbers:
n = -1
p = 0
not_a_num = 1
CAR_LOOP2:
c = ARRAY_SRC[ p ]
if ( c >= '0' ) & ( c <= '9' ) { 
	if not_a_num = 1 { n + 1 }
	ARRAY_RESULT[ n ] = ARRAY_RESULT[ n ] * 10
	ARRAY_RESULT[ n ] = ARRAY_RESULT[ n ] + ( c - '0' );
	not_a_num = 0
} else { not_a_num = 1 }
p + 1
if p < str_size { go CAR_LOOP2 }
ret

skip_arrays:

ARRAY_SRC = per_text
CREATE_ARRAY
per = ARRAY_RESULT

cur_buf = -1
buf_id1 = 0
buf_id2 = 0
tick_buf1 = new_string( SOUND_BUF_SIZE * CHANNELS )
tick_buf2 = new_string( SOUND_BUF_SIZE * CHANNELS )

tick_cnt = 0

ret

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SOUND_HANDLER:
if cur_buf = -1 { 
	cur_buf = 0
	RENDER_BUFFER
} else {
	if cur_buf = 0 {
		if get_sound_status( 0 ) != 0 { cur_buf = 1 RENDER_BUFFER }
	} else {
		if get_sound_status( 1 ) != 0 { cur_buf = 0 RENDER_BUFFER }
	}
}
ret

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

RENDER_BUFFER:
buf = tick_buf1 + cur_buf
buf_size = SOUND_BUF_SIZE
RENDER_PIECE
send_sound_to( cur_buf, buf, FREQ, CHANNELS, 0 )
ret

RENDER_PIECE:

TICK_SIZE = ( (FREQ*60) / bpm ) / 4
ptr = 0
next_piece:
size = buf_size
if tick_cnt+size > TICK_SIZE { size = TICK_SIZE - tick_cnt }
if ptr + size > buf_size { size = buf_size - ptr }

//RENDER size SAMPLES:
p = ptr while( p < ptr + size )
{
	buf[ p ] = 0
	p + 1
}
ch = 0 while( ch < pat_ys + 1 ) 
{
	vol = pvol[ ch ]
	smp = samples[ psmp[ ch ] ]
	smp_size = get_string_size( smp )
	note = pnote[ ch ]
	finetune = fine[ psmp[ ch ] ]
	smp_ptr = pptr[ ch ]
	if vol
	{
		delta = ( ( 3546894 / FREQ ) * 1024 ) / per[ note + finetune*60 ]
		p = ptr while( p < ptr + size )
		{
			v = buf[ p ] + ( smp[ smp_ptr / 1024 ] * vol ) / 16
			if v > 127 { v = 127 } 
			if v < -127 { v = -127 }
			buf[ p ] = v
			smp_ptr + delta
			if smp_ptr / 1024 >= smp_size { p = 9999999 vol = 0 pvol[ ch ] = 0 }
			p + 1
		}
	}
	pptr[ ch ] = smp_ptr
	ch + 1
}

ptr + size
tick_cnt + size
if tick_cnt >= TICK_SIZE 
{
	//Handle new tick:
	tick_cnt = 0
	if play {
	pat = pats[ cur_pat ]
	ch = 0 while( ch < pat_ys ) {
		if pat[ ch * pat_xs + cur_line ] {
			pvol[ ch ] = ( pat[ ch * pat_xs + cur_line ] & 15 )
			psmp[ ch ] = ( pat[ ch * pat_xs + cur_line ] / 16 ) & 15
			pnote[ ch ] = ( pat[ ch * pat_xs + cur_line ] / 256 )
			pptr[ ch ] = 0
		}
		ch + 1
	}
	cur_line + 1
	if cur_line >= pat_xs { 
		cur_line = 0 
		cur_loop - 1
		if cur_loop < 1 { cur_pat + 1 cur_loop = pats_loop[ cur_pat ] }
		redraw_gui = 1 
	}
	if cur_pat >= max_pats { cur_pat = 0 cur_loop = pats_loop[ 0 ] }
	if cur_pat > last_pat { cur_pat = 0 cur_loop = pats_loop[ 0 ] }
	}
}

if ptr < buf_size { go next_piece }

ret

CLEAR_CHANNELS:
	ch = 0 while( ch <= pat_ys ) {
		pvol[ ch ] = 0
		psmp[ ch ] = 0
		pnote[ ch ] = 0
		pptr[ ch ] = 0
		ch + 1
	}
ret

PLAY:
	CLEAR_CHANNELS
	cur_line = 0
	cur_loop = pats_loop[ 0 ]
	tick_cnt = TICK_SIZE
	play = 1
ret

PLAY2:
	CLEAR_CHANNELS
	cur_line = 0
	cur_pat = 0
	cur_loop = pats_loop[ 0 ]
	tick_cnt = TICK_SIZE
	play = 1
ret

STOP:
	CLEAR_CHANNELS
	play = 0
	cur_line = 0
	cur_loop = pats_loop[ 0 ]
	tick_cnt = TICK_SIZE
ret

//##########################################################################
//##########################################################################
//##########################################################################
//##########################################################################
//##########################################################################

SAVE_INT:
	fputc( (val&255), f )
	fputc( ((val/256)&255), f )
	fputc( ((val/(256*256))&255), f )
	fputc( ((val/(256*256*256))&255), f )
ret

LOAD_INT:
	val = fgetc( f )
	val = val | ( fgetc( f ) * 256 )
	val = val | ( fgetc( f ) * 256*256 )
	val = val | ( fgetc( f ) * 256*256*256 )
ret

SAVE_STRING:
	size = get_string_size( data )
	pp = 0 while( pp < size ) {
		fputc( data[ pp ], f )
		pp + 1
	}
ret

LOAD_STRING:
	size = get_string_size( data )
	pp = 0 while( pp < size ) {
		data[ pp ] = fgetc( f )
		pp + 1
	}
ret

SAVE_ARRAY:
	size = get_array_size( data )
	pp = 0 while( pp < size ) {
		val = data[ pp ] SAVE_INT
		pp + 1
	}
ret

LOAD_ARRAY:
	size = get_array_size( data )
	pp = 0 while( pp < size ) {
		LOAD_INT data[ pp ] = val
		pp + 1
	}
ret

SAVE_SONG:
	f = fopen( filename, "wb" )
	if f {
		val = 2 SAVE_INT //Version
		val = bpm SAVE_INT
		val = gvol SAVE_INT
		val = max_pats SAVE_INT
		val = pat_xs SAVE_INT
		val = pat_ys SAVE_INT
		val = last_pat SAVE_INT
		val = max_samples SAVE_INT
		p = 0 while( p < max_pats )
		{
			data = pats[ p ] SAVE_ARRAY
			p + 1
		}
		s = 0 while( s < max_samples )
		{
			val = get_string_size( samples[ s ] ) SAVE_INT
			data = samples[ s ] SAVE_STRING
			s + 1
		}
		data = pats_loop SAVE_STRING
		s = 0 while( s < max_samples )
		{
			fputc( fine[ s ], f )
			s + 1
		}
		fclose( f )
	}
ret

LOAD_SONG:
	f = fopen( filename, "rb" )
	if f {
//close old data: -------
		p = 0 while( p < max_pats )
		{
			remove_pixi( pats[ p ] )
			p + 1
		}
		s = 0 while( s < max_samples )
		{
			remove_pixi( samples[ s ] )
			s + 1
		}
		remove_pixi( pats_loop )
		remove_pixi( pats )
		remove_pixi( samples )
//-----------------------
		LOAD_INT vers = val //Version
		LOAD_INT bpm = val
		LOAD_INT gvol = val
		sound_volume( gvol )
		LOAD_INT max_pats = val
		LOAD_INT pat_xs = val
		LOAD_INT pat_ys = val
		LOAD_INT last_pat = val
		LOAD_INT max_samples = val
		max_pats = max_pats & 255
		max_samples = max_samples & 255
		pat_xs = pat_xs & 255
		pat_ys = pat_ys & 31
		pats_loop = new_string( max_pats )
		pats = new_array( max_pats )
		samples = new_array( max_samples )
		p = 0 while( p < max_pats )
		{
			pats[ p ] = new_array( pat_xs * pat_ys )
			data = pats[ p ] LOAD_ARRAY
			p + 1
		}
		s = 0 while( s < max_samples )
		{
			LOAD_INT smp_size = val
			samples[ s ] = new_string( smp_size )
			data = samples[ s ] LOAD_STRING
			s + 1
		}
		data = pats_loop LOAD_STRING
		if vers > 1 {
			s = 0 while( s < max_samples )
			{
				fine[ s ] = fgetc( f )
				s + 1
			}
		}
		else
		{
			s = 0 while( s < max_samples )
			{
				fine[ s ] = 0
				s + 1
			}
		}
		fclose( f )
	}
ret

SAVE_WAV:
	prev_freq = FREQ
	FREQ = EXPORT_FREQ
	TICK_SIZE = ( (FREQ*60) / bpm ) / 4
 	//Get song size in bytes
	len = 0
	p = 0 while( p <= last_pat ) 
	{ 
		len = len + ( pat_xs * TICK_SIZE ) * pats_loop[ p ]
		p + 1 
	}

	f = fopen( filename, "wb" )
	if( f )
	{
		//WAV HEADER:
		data = "RIFF" SAVE_STRING
		val = 4 + 24 + 8 + len //WAVE + Fmt + Data
		SAVE_INT
		data = "WAVE" SAVE_STRING
		
		//WAV FORMAT:
		data = "fmt " SAVE_STRING
		val = 16 SAVE_INT
		fputc( 1, f ) fputc( 0, f ) //format
		fputc( 1, f ) fputc( 0, f ) //channels
		val = FREQ SAVE_INT //samples per second
		val = FREQ SAVE_INT //bytes per second
		fputc( 1, f ) fputc( 0, f ) //sample size = 1 byte
		fputc( 8, f ) fputc( 0, f ) //bits

		//DATA:
		data = "data" SAVE_STRING
		val = len SAVE_INT
		gptr = 0
		PLAY2
		buf = new_string( SOUND_BUF_SIZE * CHANNELS )
		while( gptr < len )
		{
			buf_size = SOUND_BUF_SIZE
			if gptr + buf_size > len { buf_size = len - gptr }
			RENDER_PIECE
			ff = 0 while( ff < buf_size ) { buf[ ff ] = buf[ ff ] + 128 ff + 1 }
			data = buf
			SAVE_STRING
			gptr + buf_size
			px = ( (gptr/1000) * 1024 ) / (len/1000)
			px = ( px * xsize ) / 1024
			fbox( -hy, 16, px, 8, YELLOW )
			frame( 0 )
		}
		remove_pixi( buf )
		STOP

		fclose( f )
	}

	FREQ = prev_freq
ret

LOAD_WAV_SAMPLE:
	transp( 200 )
	clear( BLACK )
	transp( 256 )
	cony = -hy + 1
	f = fopen( filename, "rb" )
	if( f )
	{
		chunk = new_array( 2 ) //Chunk type and size
    		channels = 1
		bits = 16

		fseek( f, 8 + 4, 1 )

		while( 1 ) 
		{
if feof( f ) != 0 { go wavok }
data = chunk LOAD_ARRAY
handled = 0
if data[ 0 ] = ( 'f' | ('m'*256) | ('t'*256*256) | (' '*256*256*256) ) { //'fmt ':
	fseek( f, 2, 1 ) //Format
	channels = fgetc( f ) channels + fgetc( f )*256
	print( "FORMAT ($channels)", -hx + 1, cony, WHITE ) cony + 8
	frame( 0 )
	fseek( f, 10, 1 ) //Some info
	bits = fgetc( f ) bits + fgetc( f )*256
	other_info = 16 - chunk[ 1 ]
	if other_info { fseek( f, other_info, 1 ) }
	handled = 1
}
if data[ 0 ] = ( 'd' | ('a'*256) | ('t'*256*256) | ('a'*256*256*256) ) { //'data':
	print( "DATA", -hx + 1, cony, WHITE ) cony + 8
	frame( 0 )
	len = data[ 1 ] / ( channels * (bits/8) )
	print( "LEN: $len", -hx + 1, cony, WHITE ) cony + 8
	remove_pixi( samples[ cur_sample ] )
	samples[ cur_sample ] = new_string( len )
	smp = samples[ cur_sample ]
	p = 0 while( p < len ) 
	{
		if ( channels = 1 ) & ( bits = 8 ) { smp[ p ] = fgetc( f ) smp[ p ] = smp[ p ] + 128 }
		if ( channels = 2 ) & ( bits = 8 ) { smp[ p ] = fgetc( f ) smp[ p ] = smp[ p ] + 128 fgetc( f ) }
		if ( channels = 1 ) & ( bits = 16 ) { 
			v = fgetc( f )
			v + fgetc( f ) * 256
			if v >= 32768 { v - 65536 } //16bit sign control
			smp[ p ] = v / 256
		}
		if ( channels = 2 ) & ( bits = 16 ) { 
			v = fgetc( f )
			v + fgetc( f ) * 256 
			if v >= 32768 { v - 65536 } //16bit sign control
			smp[ p ] = v / 256
			fgetc( f ) fgetc( f )
		}
		p + 1
	}
	handled = 1
	go wavok
}
if handled = 0 { print( "NOT HANDLED", -hx + 1, cony, WHITE ) cony + 8 fseek( f, chunk[ 1 ], 1 ) }
		}
wavok:

		remove_pixi( chunk )
		fclose( f )
	}
ret